views:

368

answers:

4

When unit-testing objects which have a composition relationship with another object (a "has-a" relationship), as I understand it, you can only really mock the composed objects if you are using dependency injection of some sort. Hence, code of the following kind make unit-testing very difficult and might therefore be considered a bad thing:

<?php
class aSampleClass {
    private $dependency;
    public function __construct() {
        $this->dependency = new otherClass;
    }
}

This toy example is easily converted to using dependency injection by passing an instance of an otherClass object as a parameter to the constructor, but that's not always the case. Is object composition of the above form (where the "new" operator is used directly in a class implementation) a bad thing? Should you always try and write a class so that it can be fully tested in isolation of its associations?

Using dependency injection seems to run aground for me when you are using simple Value objects (in the parlance of domain-driven design) such as a date, or a money object. In those cases, it just seems to make sense to directly instantiate the Value object in question. For instance:

<?php
    class anotherSampleClass {
        public function getTimeDifferencePhrase() {
            $now = new date_Time;
            $then = new date_Time(time()-60*60*24);
            return $now->relativeTimePhrase($then);
        }
    }

Surely, in this example, it makes more sense for the unit tests of anotherSampleClass to also exercise the implementation of the date_Time objects rather than trying to use mock objects or test doubles.

Thoughts?

A: 

There isn't a definite rule one should follow in these scenarios. Dependency Injection is usually a good thing, but it's not always necessary. It's about analyzing your class and figuring out who should really have the responsibility of creating dependencies.

If you're working with very simple objects that, semantically, belong to your class and your class is completely responsible for them, then dependency injection might be over-engineering. You really don't need to test date_Time, so I wouldn't bother injecting that particular dependency.

One other thing to consider is whether having that dependency built within the constructor might make your class untestable. It happens, for example, with classes that use random number generators. In that case if you don't use dependency injection there really isn't a way to inject a generator that will give you a predictable set of numbers suitable for testing.

So, short answer: It's usually a good thing, but by no means always necessary.

jrcalzada
A: 

There is no hard-and-fast rule for something like this. Some purists would say you should inject the dependency, while others would go for a more pragmatic approach. Since the VO itself doesn't have any dependencies itself, I would probably invoke the KISS principle and say it's totally fine to "new" it up in the object. This is especially true the VO resides in the same module (in DDD terms.) Moreover, instantiating the VO in the object doesn't make it any less testable.

bingle
+1  A: 

It depends on what you're testing. Dependency Injection solves the problem of testing your class, without having to worry about it's dependencies on outside services (which may fail, not have test data, or otherwise be unsuitable for a unit test).

You wouldn't mock a value object (or a string, int, etc.) just to test that your class correctly constructed it and called the difference operator...that's all part of the implementation and isn't really relevant to testing it.

You would, however, test that your getRelativeTimeDifferencePhrase correctly returns "24 hours ago" when passed 60 * 60 * 24 seconds.

You will then realize that your hard coding time() leads to a fragile test - as you can't predict with enough accuracy what time() will return when your code runs. This will lead to a RealTimeService, which will introduce a seam that you can control.

Having your class instantiate a RealTimeService will leave you no way to inject your MockTimeService - so that you can hard code what time() it is, so you then will end up passing an ITimeService to your constructor. Now, you have dependency injection. ;)

Mark Brackett
A: 

Dependency injection does indeed solves a lot of problems. However, many people fail to see that it is an aggregation not a composition. In the example where you instantiate otherClass you have a composition. Therefore, by introducing dependency injection you are really breaking both the Composition and the Law of Demeter and introduce an aggregation.

I think the dependency injection is great as long as it doesn't break the architecture. Many people say that the use of new operator in a constructor is bad and instead an instance should be passed into constructor, but they are mistaken. It should depend of the domain. There are situation when it may even lead to confusion especially in languages with no garbage collection. For example, the rule of thumb in C++ is that the creator destroys an object. So if a Phone that has a Battery is destroyed, who's going to destroy the Battery? The Phone or whatever object passed it into the Phone? But in some situation you would want to pass the Battery into the Phone. For example if you're modeling a factory.

So, to answer your question "Is object composition without dependency injection a bad thing?" - it depends on the domain you're modeling, sacrificing design over testability is a bad thing IMO. If you find something untestable then look if your design is right. I would usually see if I can introduce dependency injection. If it's out of the question then I see if I can introduce factory methods. If not then I'll see if I can do something else.

Maksym Bykovskyy