Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design By Contract, writing test-friendly code, object construction and Dependency Injection putting all together best practices

I have been trying to figure out the best practices to write test-friendly code, but more specifically the practices related to object construction. In the blue book we discovered that we should enforce invariants when creating objects to avoid the corruption of our entities, value objects, etc. with this thought in mind, Design By Contract seems like the solution to avoid the corruption of our objects, but when we follow this, we could end up writing code like this:

class Car
{
   //Constructor
   public Car(Door door, Engine engine, Wheel wheel)
   {
      Contract.Requires(door).IsNotNull("Door is required");
      Contract.Requires(engine).IsNotNull("Engine is required");
      Contract.Requires(wheel).IsNotNull("Wheel is required");
      ....
   }
   ...
   public void StartEngine()
   {
      this.engine.Start();
   }
}

Well this looks good at first sight right? It seems we are building a safe class exposing the contract required so every time a Car object is created we can know for sure that the object is "valid".

Now let's see this example from a testing-driven point of view.

I want to build test-friendly code but in order to be able to test in isolation my Car object I need to create either a mock a stub or a dummy object for each dependency just to create my object, even when perhaps I just want to test a method that only uses one of these dependencies like the StartEngine method. Following Misko Hevery philosophy of testing I'd like to write my test specifying explicitly that I do not care about the Door or Wheel objects just passing null reference to the constructor, but since I am checking for nulls, I just can't do it

This is just a small piece of code but when you are facing a real application writing tests becomes harder and harder because you have to resolve dependencies for your subject

Misko proposes that we should not abuse of null-checks in the code (which contradicts Design By Contract) because of doing it, writing tests becomes a pain, as an alternative he sais it's better to write more tests than "have just the ilussion that our code is safe just because we have null-checks everywhere"

What are your thoughts on this? How would you do it? What should be the best practice?

like image 984
Jupaol Avatar asked Mar 14 '12 10:03

Jupaol


3 Answers

I need to create either a mock a stub or a dummy object for each dependency

This is commonly stated. But I think it is wrong. If a Car is associated with an Engine object, why not use a real Engine object when unit testing your Car class?

But, someone will declare, if you do that you are not unit testing your code; your test depends on both the Car class and the Engine class: two units, so an integration test rather than a unit test. But do those people mock the String class too? Or HashSet<String>? Of course not. The line between unit and integration testing is not so clear.

More philosophically, you can not create good mock objects in many cases. The reason is that, for most methods, the manner in which an object delegates to associated objects is undefined. Whether it does delegate, and how, is left by the contract as an implementation detail. The only requirement is that, on delegating, the method satisfies the preconditions of its delegate. In such a situation, only a fully functional (non-mock) delegate will do. If the real object checks its preconditions, failure to satisfy a precondition on delegating will cause a test failure. And debugging that test failure will be easy.

like image 55
Raedwald Avatar answered Oct 01 '22 03:10

Raedwald


Have a look at the concept of test data builders.

You create the builder once with preconfigured data, override a property if neccessary and call Build() to get a new instance of your system under test.

Or you can have a look at the sources of the Enterprise Library. The tests contain a base class called ArrangeActAssert that provides nice support for BDD-ish tests. You implement your test setup in the Arrange method of a class derived from AAA and it will be called whenever you run a specific test.

like image 21
Sebastian Weber Avatar answered Oct 01 '22 03:10

Sebastian Weber


I solve this problem in the unit tests:

My test class for the car would look like:

public sealed class CarTest
{
   public Door Door { get; set; }
   public Engine Engine { get; set; }
   public Wheel Wheel { get; set; }

   //...

   [SetUp]
   public void Setup()
   {
      this.Door = MockRepository.GenerateStub<Door>();
      //...
   }

   private Car Create()
   {
      return new Car(this.Door, this.Engine, this.Wheel);
   }
}

Now, in the test methods, I only need to specify the "interesting" objects:

public void SomeTestUsingDoors()
{
   this.Door = MockRepository.GenerateMock<Door>();
   //... - setup door

   var car = this.Create();
   //... - do testing
}
like image 43
Matthias Avatar answered Oct 01 '22 04:10

Matthias