0

Let's say we have this method:

string Add(int a, int b) {
    var sum = _calculator.Add(a,b);
    var response = _formatter.Format(sum);
    return response;
}

Now I want to unit-test this method. Assume of course the code is not actually that trivial, _calculator and _formatter might be external services, there's some logic in the method itself, and I want to make sure I'm calling all of my dependencies correctly and return the correct result. Of course _calculator and _formatter will be mocked, but what should I mock and what should I verify? I see too options -

Setup the mocks to respond to any input with specific output and later make sure they were called with the expected input:

calculator = Substitute.For<ICalculator>();
calculator.Add(Arg.Any<int>(), Arg.Any<int>()).returns(123);
formatter = Substitute.For<IFormatter>();
formatter.Format(Arg.Any<int>()).returns("yup");

var subject = new DidntThinkOfClassName(calculator, formatter);
var res = subject.Add(1, 2);

calculator.Received(1).Add(1, 2);
formatter.Received(1).Format(123);
res.ShouldBe("yup");

Or setup the mocks to ONLY respond to the expected input, and then only verify the end result:

calculator = Substitute.For<ICalculator>();
calculator.Add(1, 2).returns(123);
formatter = Substitute.For<IFormatter>();
formatter.Format(123).returns("yup");

var subject = new DidntThinkOfClassName(calculator, formatter);
var res = subject.Add(1, 2);

res.ShouldBe("yup");

In the first option I'm accepting any input, which means simpler mocks, but I then have to verify the received calls. In the second option I arrange my mocks in such a way that the end result can only be achieved if each and every mock received exactly what it was configured to receive, so I only need to check the end result.

What would you say is better? Is there a better solution i'm missing?

1 Answers1

2

Now I want to unit-test this method. Assume of course the code is not actually that trivial, _calculator and _formatter might be external services, there's some logic in the method itself, and I want to make sure I'm calling all of my dependencies correctly and return the correct result. Of course _calculator and _formatter will be mocked, but what should I mock and what should I verify?

There are a couple talks that will help you to understand your question.

In short: when you are introducing test doubles, you white box your test designs. In particular, you pay attention to how the dependencies are being used.

If the calls to your test doubles are queries, then you don't bother worrying about the outgoing messages at all. Just stick in a test double with the correct answer hard coded into it, and test the behavior of the subject.

(Listed first, because the code you have written suggests that Calculator::Add and Formatter::Format are queries. See Command Query Separation).

If the calls to the dependencies are supposed to have side effects on the dependencies themselves, then you might have a test that mocks the dependency to verify that the correct arguments are passed to the correct method.

I’d have loved to see her dig down a bit more on interactions which are commands and queries at the same time. How do you handle this case ?

Test the two pieces separately. Write one test that exercises the test subject, and confirms that it sent the correct messages; write a separate test that exercises the test subject and confirms that the result is satisfactory.

VoiceOfUnreason
  • 34,589
  • 2
  • 44
  • 83