代码之家  ›  专栏  ›  技术社区  ›  Simon Randy Burden

如何模拟System.DirectoryServices.SearchResult?

  •  5
  • Simon Randy Burden  · 技术社区  · 15 年前

    如果您有一个需要测试的方法,它将获取搜索结果列表

    public virtual void ProcessResults(IList<SearchResult> list)
    {
        //Code to tests here
    }
    

    如何模拟搜索结果列表?

    注意:不允许使用低级注入框架(如typemock)。

    3 回复  |  直到 6 年前
        1
  •  9
  •   Simon Randy Burden    6 年前

    现在我有一个丑陋的密码

    public static class SearchResultFactory
    {
        const BindingFlags nonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance;
        const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance;
    
        public static SearchResult Construct<T>(T anonInstance)
        {
            var searchResult = GetUninitializedObject<SearchResult>();
            SetPropertiesFieled(searchResult);
            var dictionary = (IDictionary)searchResult.Properties;
            var type = typeof(T);
            var propertyInfos = type.GetProperties(publicInstance);
            foreach (var propertyInfo in propertyInfos)
            {
                var value = propertyInfo.GetValue(anonInstance,null);
                var propertyCollection = GetUninitializedObject<ResultPropertyValueCollection>();
                var innerList = GetInnerList(propertyCollection);
                if (propertyInfo.PropertyType.IsArray)
                {
                    var stringArray = (String[])value;
                    foreach (var subValue in stringArray)
                    {
                        innerList.Add(subValue);
                    }
                }
                else
                {
                    innerList.Add(value);
                }
                var lowerKey = propertyInfo.Name.ToLower(CultureInfo.InvariantCulture);
                dictionary.Add(lowerKey, propertyCollection);
            }
            return searchResult;
        }
    
        private static ArrayList GetInnerList(object resultPropertyCollection)
        {
            var propertyInfo = typeof(ResultPropertyValueCollection).GetProperty("InnerList", nonPublicInstance);
            return (ArrayList) propertyInfo.GetValue(resultPropertyCollection, null);
        }
    
        private static void SetPropertiesFieled(SearchResult searchResult)
        {
            var propertiesFiled = typeof(SearchResult).GetField("properties", nonPublicInstance);
            propertiesFiled.SetValue(searchResult, GetUninitializedObject<ResultPropertyCollection>());
        }
    
        private static T GetUninitializedObject<T>()
        {
            return (T) FormatterServices.GetUninitializedObject(typeof(T));
        }
    }
    

    这是用来…

    var searchResult = SearchResultFactory.Construct(
             new
             {
                 name = "test1",
                 givenName = "John",
                 sn = "Smith",
                 rights = new String[] { "READ", "WRITE" }
             });
    
        2
  •  2
  •   ScottBai    14 年前

    ,如果您打算进行任何数量的广告编程,并且希望能够测试它,那么可以考虑编写一个包装器来代替 两个 SearchResult和DirectoryEntry——这样做的好处是,您不必为每个需要获取SearchResult或DirectoryEntry的函数编写两个函数。

    我做了类似的事情。这不完全是一个晚上的项目,但完全值得,因为我正在研究一个ISV广告产品。你可以少包装,减少工作量。下面是一个伪代码布局,让您了解:

          DirectoryObject : IDirectoryObject, IDisposable (Important!)
              ctor (DirectoryEntry)
              ctor (SearchResult)
              ctor (string Path)
              string Path
              bool IsValid 
              Search(with a gazillion overloads)
              DirectoryObjectPropertyCollection Properties 
              //(which itself uses DirectoryObjectPropertyValueCollection to wrap PropertyValueCollection)
    
          //To get at the native underlying objects if necessary since I only wrapped commonly used elements
          DirectoryEntry NativeDirectoryEntry  
          SearchResult NativeSearchResult
    
          //So I know whether to grab the native SearchResult or DirectoryEntry
          IsDirectoryEntry
          IsSearchResult
    

    这种方法——除了增加了可测试性之外——使我不必在我们共享的libaries中做如下的事情:

      public void DoSomethingWithAUser(DirectoryEntry user,...)
      public void DoSomethingWithAUser(SearchResult user,...)
      public void DoSomethingWithAUser(string userPath,...)
    

    现在我们只有

      public void DoSomethingWithAUser(DirectoryObject user,...)
    
        3
  •  0
  •   benPearce    15 年前

    您可以围绕SearchResult编写自己的包装类,实现一些ISearchResult接口。

    具体的实现使用searchresult类在内部公开您需要的内容,然后您可以在测试时模拟接口。