Unit Testing – How to Reduce Coupling in Unit Tests

couplingunit testing

As a developer I should strive for low coupling between classes.

But low coupling doesn't mean "No coupling" so sometimes I have to allow some code flexibility and use "new" inside a domain model. (I'm sure everybody does this in real production code)

If I use "new" inside a method to create an object and I have to unit test this method I got a problem. Because I can't mock the objects I can't test the method in isolation. I know I can use dependency injection or I can send objects as parameters but I'm not talking about this clear cases.

Is this acceptable in practice?
Is there a better way? (I can't always inject)
Is this a unit test or an integration test?

PHP example:

class Car {
   protected $objDoor;
   public function createComponents() {
       $this->objDoor = new Door();
   }
}

Best Answer

Dependency Injection

I think is strongly depends on what object you are creating. If you create object that you then return, it is somewhat part of the specification of the method. In that case it would be basically possible to do a unit test.

As you would do a unit test for the class in question (the one you use new on) as well, this shouldn't be the main problem. But if you create an object and do some stuff with that object (produce side-effects), you should use injection. This is true even more if you get all the parameters for the constructor call as parameters of your method. Simply create the object before calling the method and give the reference instead.

But of course that would imply that the method in which the object is created, would be doing the same thing now.

That being said you will need some kind of central mechanism that handles the dependency injection. Symfony provides a Dependency Injection component that handles that stuff.

Code coverage

It is important to have code coverage. It depends strongly on your project how well that can be done. Whenever possible unit tests should be written. On top of that you should use functional tests that test a certain function (and thereby the interaction of needed classes). All in all that should fit your need.