It seems to me that mocks are testing implementation.
Specifically, they test that the way that the implementation interacted with a particular object.
100% correct. However, this is still Unit testing, just from a different perspective.
Let's say you have a method that's supposed to perform a function on 2 numbers using some kind of MathsService
. MathsService
is given to a Calculator
class in order to do the math for the calculator.
Let's pretend MathsService
has a single method, PerformFunction(int x, int y)
that is supposed to just return x+y
.
Testing like this: (all below = pseudo code, with certain bits left out for clarity)
var svc = new MathsService();
var sut = new Calculator(svc);
int expected = 3;
int actual = sut.Calculate(1,2);
Assert.AreEqual(expected,actual,"Doh!");
That's a black box test of the unit Calculator.Calculate()
. Your test doesn't know or care how the answer was arrived at. It's important because it gives you a certain level of confidence that your test works correctly.
However, consider this implementation of Calculator.Calculate:
public int Calculate()
{
return 4;
}
Testing like this:
var svc = new Mock<IMathsService>(); //did I mention there was an interface? There's an interface...
svc.Setup(s=>PerformCalculation(1,2)).Returns(3);
var sut new Calculator(svc.Object);
sut.Calculate(1,2);
svc.Verify(s=>PerformCalculation(1,2),Times.Once,"Calculate() didn't invoke PerformFunction");
This white box test doesn't tell you anything about the correctness of the PerformFunction
method, but it does prove that, regardless of the result, the Calculator
did pass x and y to the IAdditionService.PerformCalculation
method, which is what you want it to do.
You can of course write other tests to verify that the result of the PerformCalculation
test is passed back without modification to the caller, etc.
Armed with this knowledge, if your first unit test now fails, you can, with a high degree of confidence, jump right into the MathService
class to look for problems because you know that the issue is likely not the Calculator.Calculate
method.
Hope that helps...