Как издеваться над System.DirectoryServices.SearchResult? - PullRequest
5 голосов
/ 15 января 2010

Если у вас есть метод, который необходимо протестировать, который принимает список SearchResults

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

Как создать макет этого списка SearchResult?

Примечание. Нет низкоуровневогоразрешены инъекционные рамки (например, TypeMock).

Ответы [ 3 ]

10 голосов
/ 15 января 2010

В настоящее время у меня есть этот уродливый код

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 голосов
/ 23 ноября 2010

, если вы собираетесь заниматься программированием на AD и хотите протестировать его, подумайте о написании оболочки, которую вы можете использовать вместо ОБА SearchResult и DirectoryEntry - что Кстати, в качестве дополнительного преимущества вам не нужно писать две функции, которые должны принимать SearchResult или DirectoryEntry.

Я сделал что-то похожее на это. Это был не совсем вечерний проект, но он того стоил, учитывая, что я работал над продуктом ISV AD. Вы можете, вероятно, обернуть меньше и уменьшить усилия. Вот макет псевдокода, чтобы дать вам представление:

      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

Этот подход - помимо повышенной тестируемости - избавляет меня от необходимости делать что-то подобное в наших общих библиотеках:

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

и теперь у нас просто

  public void DoSomethingWithAUser(DirectoryObject user,...)
0 голосов
/ 15 января 2010

Вы можете написать свой собственный класс-оболочку для SearchResult, реализовать некоторый интерфейс ISearchResult.

Ваша конкретная реализация использует класс SearchResult, предоставляющий вам столько, сколько вам нужно, и затем вы можете высмеивать интерфейс во время тестирования.

...