Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Code that is dependency on Enterprise Library even though it doesn't provide interfaces?

Maybe I'm showing my lack of understanding of dependency injection and testing, but I don't understand how using dependency injection with classes that don't implement interfaces helps me at all with testing?

For instance, in the Enterprise Library 5.0 documentation it talks about using the Unity container to create instances. It says that this aids "testability: It is trivial to isolate classes from dependencies when using the dependency injection style." MSDN

How do I use this in my unit testing fixtures? Their example has a constructor with parameters as classes rather than interfaces:

public class TaxCalculator 
{
  private ExceptionManager _exceptionManager;
  private LogWriter _logWriter;

  public TaxCalculator(ExceptionManager em, LogWriter lw) 
  {
    this._exceptionManager = em;
    this._logWriter = lw;
  }
}
like image 690
Bob Wintemberg Avatar asked Apr 02 '12 15:04

Bob Wintemberg


2 Answers

To answer the question "How do I test Enterprise Library code": you don't. Testing other people's stuff is the job of other people. Any interfaces or abstractions in Enterprise Library or any other 3rd-party library exists for their own abstraction purposes, not for yours.

What you need to do is define your own interfaces which describe the needs of your application (logging, caching, encryption, etc.) and then write adapters which implement your interfaces using Enterprise Library (or other 3rd-party libraries). This practice is known as the Dependency Inversion Principle.

To test your own code designed in this way, for unit/component level tests you would just use Test Doubles for those interfaces you've defined yourself (e.g. IMyOwnLogger). To test the adapters you write to adapt to 3rd-party libraries, you would write integration tests. To test that it all works together, you would write acceptance tests that drive the app through the UI or subcutaneously.

For more information on this view, check out my article: "TDD Best Practices: Don't Mock Others".

like image 116
Derek Greer Avatar answered Sep 19 '22 12:09

Derek Greer


It is preferable to program against abstraction instead of implementation. But abstraction is not always interface. It could be abstract class.

public abstract class LogWriter
{
    public abstract void Write(string message);
}

So, there is no problem to create mock of abstract class:

Mock<LogWriter> logWriter = new Mock<LogWriter>();
TaxCalculator calc = new TaxCalculator(logWriter.Object);

If you not doing unit-testing, I don't see any problem to pass non-abstract parameters, because of YAGNI principle. If I don't need another implementation of ExceptionManager, then why should I create abstraction over it? But if I do TDD, then I definitely will need at least two implementations of class. One real and one mock/stub.

Btw be careful with service locator anti-pattern.

UPDATE: Didn't get that you are referring to existing classes of Microsoft.Practices.EnterpriseLibrary (which I don't like). I think thats another design failure of Microsoft.Practices team. Making 'sealed' ExceptionManager class which does not implement any interfaces/base classes kills testability.

like image 43
Sergey Berezovskiy Avatar answered Sep 19 '22 12:09

Sergey Berezovskiy