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?

  • 3
    The example code has no actual logic to unit test. Since you mentioned the real code is not that trivial, consider extracting the relevant code into it's own class and unit test that without the need for mocks. Have a look here softwareengineering.stackexchange.com/a/198988/320517 – Rik D Dec 4 '18 at 21:07
  • In my production code, I usually go with the second method you presented, as it introduces less coupling/assumptions between the test and the class under test. I may end up parametrising test inputs (TestCase in NUnit) if I want to make sure edge cases are covered. – Eternal21 Dec 6 '18 at 13:02
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.

  • That presentation from Katrina Owen was marvellously practical. 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 ? – Steve Chamaillard Dec 14 '18 at 19:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.