dimanche 23 août 2015

Too many interfaces and wrappers?

I'm slowly starting to get the hang of unit-testing and mocking, but it's a slow process. I have tried unit testing this Active Directory code. The question is not strictly relevant to AD.

class ActiveDirectoryQueryer {    
   DirectorySearcher mSearcher;

   public ActiveDirectoryQueryer() {
      var searcher = new DirectorySearcher(...);
   }

   public void GetAllMailEntries() {
      using (mSearcher)
         MailEntries =
            mSearcher
            .FindAll()
            .Select(result => result.GetDirectoryEntry())
            .Select(BuildNewADUser)
            .ToList();
   }

   static ActiveDirectoryUser BuildNewADUser(DirectoryEntry pDirectoryEntry) {
      return ActiveDirectoryUser.Create(
         pDirectoryEntry.Guid,
         (pDirectoryEntry.Properties["name"].Value ?? "").ToString(),
         (pDirectoryEntry.Properties["mail"].Value ?? "").ToString()
      );
   }

So, I would like to unit test the GetAllMailEntries method. In order to do this using MOQ I've had to manually generate interfaces and wrappers for various .NET types, and changed many of the above references to interfaces instead (like IDirectoryEntry). Each of the IXxxx interfaces below has an associated wrapper class XxxxWrapper. In total I added at least 12 new source files just for this one test. Here's what I've ended up with for the unit test:

[TestMethod]
public void TestGetAllMailEntries() {
   var mockSearcher = new Mock<IDirectorySearcher>();
   var mockResultCollection = new Mock<ISearchResultCollection>();
   var mockSearchResult = new Mock<ISearchResult>();
   var mockDirectoryEntry = new Mock<IDirectoryEntry>();
   var mockPropertyCollection = new Mock<IPropertyCollection>();
   var nameMockPropertyValueCollection = new Mock<IPropertyValueCollection>();
   var mailMockPropertyValueCollection = new Mock<IPropertyValueCollection>();

   const string name = "SomeNameValue";
   const string mailAddress = "SomeMailAddress";

   nameMockPropertyValueCollection.SetupGet(pvc => pvc.Value).Returns(name);
   mailMockPropertyValueCollection.SetupGet(pvc => pvc.Value).Returns(mailAddress);
   mockPropertyCollection.SetupGet(pc => pc["name"]).Returns(nameMockPropertyValueCollection.Object);
   mockPropertyCollection.SetupGet(pc => pc["mail"]).Returns(mailMockPropertyValueCollection.Object);
   mockDirectoryEntry.SetupGet(de => de.Properties).Returns(mockPropertyCollection.Object);
   mockSearchResult.Setup(sr => sr.GetDirectoryEntry()).Returns(mockDirectoryEntry.Object);
   mockResultCollection.Setup(results => results.GetEnumerator()).Returns(new List<ISearchResult> { mockSearchResult.Object }.GetEnumerator());
   mockSearcher.Setup(searcher => searcher.FindAll()).Returns(mockResultCollection.Object);

   var queryer = new ActiveDirectoryQueryer(mockSearcher.Object);
   queryer.GetAllMailEntries();
   Assert.AreEqual(1, queryer.MailEntries.Count());
   var entry = queryer.MailEntries.Single();
   Assert.AreEqual(name, entry.Name);
   Assert.AreEqual(mailAddress, entry.EmailAddress);
}

Is it normal to have this many interfaces and wrapper classes? (The wrappers are necessary since .NET types cannot otherwise implement my interfaces.)

Aucun commentaire:

Enregistrer un commentaire