1

我最近重构了 Active Directory 角色提供程序中的一些代码,以删除对多个域的支持。在这个过程中,我的集成测试以我没想到的方式出现了问题。除非我在测试设置代码和调用被测试方法的代码之间放置了明显的延迟,否则测试不会可靠地成功。如果我使用调试器运行测试,它总是会成功,并且我看不到代码有任何问题。如果我使用自动化工具运行测试,一个或多个测试会以意想不到的方式失败和失败。

如何可靠地测试使用 System.Directory.AccountManagement 命名空间类和方法的角色提供程序代码?

注意:为了与 SO 范式保持一致,我提供了我找到的解决方案作为单独的答案。但是,如果您认为您的解决方案比我的更好,我愿意接受其他解决方案。之所以提出这个问题,是因为我在 SO 上找不到任何解决我的问题的现有问题。

一些相关的问题是:

4

1 回答 1

0

我发现问题在于我在角色提供者中使用的 PrincipalSearchers 并不总是与设置中使用的代码联系同一个域控制器。由于域控制器之间的传播延迟,这将导致错误。为了解决这个问题,我使用构造函数注入将设置中使用的 PrincipalContext 提供给角色提供者。这允许角色提供者始终使用与测试代码相同的上下文。此外,我将 PrincipalSearcher 上的 SearchRoot 替换为基于通过构造函数注入提供的 PrincipalContext 的搜索根。相关代码如下。请注意,角色提供者实现 IDisposable 是为了在未从外部提供域上下文时处理域上下文。

private bool DisposeContext { get; set; }
private PrincipalContext DomainContext { get; set; }

public PrintAccountingRoleProvider() : this( null ) { }

public PrintAccountingRoleProvider( PrincipalContext domainContext )
{
    this.DisposeContext = domainContext == null;
    this.DomainContext = domainContext ?? new PrincipalContext( ContextType.Domain );
}

...

private UserPrincipal FindUser( string userName )
{
    using (PrincipalSearcher userSearcher = new PrincipalSearcher())
    {
        UserPrincipal userFilter = new UserPrincipal( this.DomainContext );
        userFilter.SamAccountName = userName;
        userSearcher.QueryFilter = userFilter;

        // Replace the searcher with one directly associated with the context to ensure that any changes
        // made elsewhere will be reflected if we call the search immediately following the change.  This
        // is critical in the integration tests.
        var searcher = userSearcher.GetUnderlyingSearcher() as DirectorySearcher;
        searcher.SearchRoot = new DirectoryEntry( @"LDAP://" + this.DomainContext.ConnectedServer + @"/dc=iowa,dc=uiowa,dc=edu" );

        return userSearcher.FindOne() as UserPrincipal;
    }
}

...

private void Dispose( bool disposing )
{
    if (!this.disposed)
    {
        if (disposing)
        {
            if (this.DisposeContext && this.DomainContext != null)
            {
                this.DomainContext.Dispose();
                this.DomainContext = null;
            }
        }
        this.disposed = true;
    }
}
于 2009-11-24T16:52:35.170 回答