The I have no idea what I'm testing anti-pattern.

It is no secret that I'm not a big fan of service locators in general, but even if you are a fan of those there is a pattern I really don't want to see in unit tests. I will call this the I-have-no-idea-what-I-am-testing-anti-pattern.

The anti-pattern is easily spotted because the test code itself contains calls to your service locator to resolve interfaces. In the following code you see two examples of this anti-pattern.

   1:  var bar = (FakeBar)SomeServiceLocator.Resolve<IBar>();
   2:  bar.SomeBehavior = _ => false;
   3:  var foo = SomeServiceLocator.Resolve<IFoo>();
   4:  Assert.IsTrue(foo.DoSomething());

On the first line a test double has already been registered and the test is casting to that test double hoping that is the case. Then on line three the code under test is also created through the service locator so actually you don't know what you are testing.

There is a very easy way to change this code into something acceptable.

   5:  var bar = new FakeBar();
   6:  SomeServiceLocator.Register<IBar>(bar);
   7:  bar.SomeBehavior = _ => false;
   8:  var foo = new Foo();
   9:  Assert.IsTrue(foo.DoSomething());

Obviously using constructor injection the code would IMHO be even nicer

  10:  var bar = new FakeBar();
  11:  bar.SomeBehavior = _ => false;
  12:  var foo = new Foo(bar);
  13:  Assert.IsTrue(foo.DoSomething());

Bottom line; the service locator is there to resolve dependencies in your "production" code. Not to serve as a general purpose new operator. And since your tests should know what they are testing there should be no need ever to resolve instances in test code.

No comments:

Post a Comment