Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Application Service Layer: Unit Tests, Integration Tests, or Both?

I've got a bunch of methods in my application service layer that are doing things like this:

public void Execute(PlaceOrderOnHoldCommand command)
{
    var order = _repository.Load(command.OrderId);
    order.PlaceOnHold();
    _repository.Save(order);
}

And at present, I have a bunch of unit tests like this:

[Test]
public void PlaceOrderOnHold_LoadsOrderFromRepository()
{
    var repository = new Mock<IOrderRepository>();
    const int orderId = 1;
    var order = new Mock<IOrder>();
    repository.Setup(r => r.Load(orderId)).Returns(order.Object);

    var command = new PlaceOrderOnHoldCommand(orderId);
    var service = new OrderService(repository.Object);
    service.Execute(command);

    repository.Verify(r => r.Load(It.Is<int>(x => x == orderId)), Times.Exactly(1));
}

[Test]
public void PlaceOrderOnHold_CallsPlaceOnHold()
{
            /* blah blah */
}

[Test]
public void PlaceOrderOnHold_SavesOrderToRepository()
{
            /* blah blah */
}

It seems to be debatable whether these unit tests add value that's worth the effort. I'm quite sure that the application service layer should be integration tested, though.

Should the application service layer be tested to this level of granularity, or are integration tests sufficient?

like image 849
Josh Kodroff Avatar asked Jul 12 '11 22:07

Josh Kodroff


1 Answers

I'd write a unit test despite there also being an integration test. However, I'd likely make the test much simpler by eliminating the mocking framework, writing my own simple mock, and then combining all those tests to check that the the order in the mock repository was on hold.

[Test]
public void PlaceOrderOnHold_LoadsOrderFromRepository()
{
    const int orderId = 1;
    var repository = new MyMockRepository();
    repository.save(new MyMockOrder(orderId));      
    var command = new PlaceOrderOnHoldCommand(orderId);
    var service = new OrderService(repository);
    service.Execute(command);
    Assert.IsTrue(repository.getOrder(orderId).isOnHold());
}

There's really no need to check to be sure that load and/or save is called. Instead I'd just make sure that the only way that MyMockRepository will return the updated order is if load and save are called.

This kind of simplification is one of the reasons that I usually don't use mocking frameworks. It seems to me that you have much better control over your tests, and a much easier time writing them, if you write your own mocks.

like image 118
Robert Martin Avatar answered Sep 30 '22 14:09

Robert Martin