How to mock System.DirectoryServices.SearchResult?
Currently i have this ugly code
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;
}
static ArrayList GetInnerList(object resultPropertyCollection)
{
var propertyInfo = typeof(ResultPropertyValueCollection).GetProperty("InnerList", nonPublicInstance);
return (ArrayList) propertyInfo.GetValue(resultPropertyCollection, null);
}
static void SetPropertiesFieled(SearchResult searchResult)
{
var propertiesFiled = typeof(SearchResult).GetField("properties", nonPublicInstance);
propertiesFiled.SetValue(searchResult, GetUninitializedObject<ResultPropertyCollection>());
}
static T GetUninitializedObject<T>()
{
return (T) FormatterServices.GetUninitializedObject(typeof(T));
}
}
which is used...
var searchResult = SearchResultFactory.Construct(
new
{
name = "test1",
givenName = "John",
sn = "Smith",
rights = new String[] { "READ", "WRITE" }
});
,If you're going to do any amount of AD programming, and you want to be able to test it, consider writing a wrapper that you can use in place of BOTH SearchResult and DirectoryEntry - that way as an added benefit you don't have to write two of every function that would need to take either a SearchResult or DirectoryEntry.
I did something similar to this. It was not exactly a single-evening project, but totally worth it given that I was working on an ISV AD product. You can probably wrap less and decrease effort. Here's a pseudocode layout to give you an idea:
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
This approach - besides the increased testability - saves me from having to do things like the following in our shared libaries:
public void DoSomethingWithAUser(DirectoryEntry user,...)
public void DoSomethingWithAUser(SearchResult user,...)
public void DoSomethingWithAUser(string userPath,...)
and now we just have
public void DoSomethingWithAUser(DirectoryObject user,...)