Question

TL;DR
How do you test a value object in isolation from its dependencies without stubbing or injecting them?


In Misko Hevery's blog post To “new” or not to “new”… he advocates the following (quoted from the blog post):

  • An Injectable class can ask for other Injectables in its constructor.(Sometimes I refer to Injectables as Service Objects, but that term is overloaded.). Injectable can never ask for a non-Injectable (Newable) in its constructor.
  • Newables can ask for other Newables in their constructor, but not for Injectables (Sometimes I refer to Newables as Value Object, but again, the term is overloaded)

Now if I have a Quantity value object like this:

class Quantity{

    $quantity=0;

    public function __construct($quantity){
        $intValidator = new Zend_Validate_Int();
        if(!$intValidator->isValid($quantity)){
            throw new Exception("Quantity must be an integer.");    
        }

        $gtValidator = new Zend_Validate_GreaterThan(0);
        if(!$gtvalidator->isValid($quantity)){
            throw new Exception("Quantity must be greater than zero."); 
        }

        $this->quantity=$quantity;  
    }
}

My Quantity value object depends on at least 2 validators for its proper construction. Normally I would have injected those validators through the constructor, so that I can stub them during testing.

However, according to Misko a newable shouldn't ask for injectables in its constructor. Frankly a Quantity object that looks like this
$quantity=new Quantity(1,$intValidator,$gtValidator); looks really awkward.

Using a dependency injection framework to create a value object is even more awkward. However now my dependencies are hard coded in the Quantity constructor and I have no way to alter them if the business logic changes.

How do you design the value object properly for testing and adherence to the separation between injectables and newables?

Notes:

  1. This is just a very very simplified example. My real object my have serious logic in it that may use other dependencies as well.
  2. I used a PHP example just for illustration. Answers in other languages are appreciated.
Was it helpful?

Solution

A Value Object should only contain primitive values (integers, strings, boolean flags, other Value Objects, etc.).

Often, it would be best to let the Value Object itself protect its invariants. In the Quantity example you supply, it could easily do that by checking the incoming value without relying on external dependencies. However, I realize that you write

This is just a very very simplified example. My real object my have serious logic in it that may use other dependencies as well.

So, while I'm going to outline a solution based on the Quantity example, keep in mind that it looks overly complex because the validation logic is so simple here.

Since you also write

I used a PHP example just for illustration. Answers in other languages are appreciated.

I'm going to answer in F#.

If you have external validation dependencies, but still want to retain Quantity as a Value Object, you'll need to decouple the validation logic from the Value Object.

One way to do that is to define an interface for validation:

type IQuantityValidator =
    abstract Validate : decimal -> unit

In this case, I patterned the Validate method on the OP example, which throws exceptions upon validation failures. This means that if the Validate method doesn't throw an exception, all is good. This is the reason the method returns unit.

(If I hadn't decided to pattern this interface on the OP, I'd have preferred using the Specification pattern instead; if so, I'd instead have declared the Validate method as decimal -> bool.)

The IQuantityValidator interface enables you to introduce a Composite:

type CompositeQuantityValidator(validators : IQuantityValidator list) =
    interface IQuantityValidator with
        member this.Validate value =
            validators
            |> List.iter (fun validator -> validator.Validate value)

This Composite simply iterates through other IQuantityValidator instances and invokes their Validate method. This enables you to compose arbitrarily complex validator graphs.

One leaf validator could be:

type IntegerValidator() =
    interface IQuantityValidator with
        member this.Validate value =
            if value % 1m <> 0m
            then
                raise(
                    ArgumentOutOfRangeException(
                        "value",
                         "Quantity must be an integer."))

Another one could be:

type GreaterThanValidator(boundary) =
    interface IQuantityValidator with
        member this.Validate value =
            if value <= boundary
            then
                raise(
                    ArgumentOutOfRangeException(
                        "value",
                         "Quantity must be greater than zero."))

Notice that the GreaterThanValidator class takes a dependency via its constructor. In this case, boundary is just a decimal, so it's a Primitive Dependency, but it could just as well have been a polymorphic dependency (A.K.A a Service).

You can now compose your own validator from these building blocks:

let myValidator =
    CompositeQuantityValidator([IntegerValidator(); GreaterThanValidator(0m)])

When you invoke myValidator with e.g. 9m or 42m, it returns without errors, but if you invoke it with e.g. 9.8m, 0m or -1m it throws the appropriate exception.

If you want to build something a bit more complicated than a decimal, you can introduce a Factory, and compose the Factory with the appropriate validator.

Since Quantity is very simple here, we can just define it as a type alias on decimal:

type Quantity = decimal

A Factory might look like this:

type QuantityFactory(validator : IQuantityValidator) =
    member this.Create value : Quantity =
        validator.Validate value
        value

You can now compose a QuantityFactory instance with your validator of choice:

let factory = QuantityFactory(myValidator)

which will let you supply decimal values as input, and get (validated) Quantity values as output.

These calls succeed:

let x = factory.Create 9m
let y = factory.Create 42m

while these throw appropriate exceptions:

let a = factory.Create 9.8m
let b = factory.Create 0m
let c = factory.Create -1m

Now, all of this is very complex given the simple nature of the example domain, but as the problem domain grows more complex, complex is better than complicated.

OTHER TIPS

Avoid value types with dependencies on non-value types. Also avoid constructors that perform validations and throw exceptions. In your example I'd have a factory type that validates and creates quantities.

Your scenario can also be applied to entities. There are cases where an entity requires some dependency in order to perform some behaviour. As far as I can tell the most popular mechanism to use is double-dispatch.

I'll use C# for my examples.

In your case you could have something like this:

public void Validate(IQuantityValidator validator)

As other answers have noted a value object is typically simple enough to perform its invariant checking in the constructor. An e-mail value object would be a good example as an e-mail has a very specific structure.

Something a bit more complex could be an OrderLine where we need to determine, totally hypothetical, whether it is, say, taxable:

public bool IsTaxable(ITaxableService service)

In the article you reference I would assert that the 'newable' relates quite a bit to the 'transient' type of life cycle that we find in DI containers as we are interested in specific instances. However, when we need to inject specific values the transient business does not really help. This is the case for entities where each is a new instance but has very different state. A repository would hydrate the object but it could just as well use a factory.

The 'true' dependencies typically have a 'singleton' life-cycle.

So for the 'newable' instances a factory could be used if you would like to perform validation upon construction by having the factory call the relevant validation method on your value object using the injected validator dependency as Mark Seemann has mentioned.

This gives you the freedom to still test in isolation without coupling to a specific implementation in your constructor.

Just a slightly different angle on what has already been answered. Hope it helps :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top