代码之家  ›  专栏  ›  技术社区  ›  tvanfosson

如何使用Active Directory角色提供程序创建可靠的集成测试?

  •  1
  • tvanfosson  · 技术社区  · 16 年前

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

    注:

    一些相关问题包括:

    1 回复  |  直到 9 年前
        1
  •  0
  •   tvanfosson    16 年前

    我发现问题在于,我在角色提供程序中使用的PrincipalSearcher与设置中使用的代码并不总是联系同一个域控制器。由于域控制器之间的传播延迟,这将导致错误。为了解决这个问题,我使用构造函数注入为角色提供程序提供设置中使用的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;
        }
    }