Although there are plenty of resources, even here on SO, only two of the terms are compared to each other in these Q/A.
So, in short, what is each one of them? And how they all relate to each other? Or don't they at all?
Difference between mock and stub is very simple - mock can make your test fail, while stub can't. That's all there is. Additionally, you can think of stub as of something that provides values. Nowadays, fake is just a generic term for both of them (more on that later).
Let's consider a case where you have to build a service that sends packages via communication protocol (exact details are irrelevant). You simply supply service with package code and it does the rest. Given the snippet below, can you identify which dependency would be a stub and which mock in potential unit test?
public class DistributionService
{
public double SendPackage(string packageCode)
{
var contents = this.packageService.GetPackageContents(packageCode);
if (contents == null)
{
throw new InvalidOperationException(
"Attempt to send non-exisiting package");
}
var package = this.packageBuilder.Build(contents);
this.packageDistributor.Send(package);
}
}
It's fairly easy to tell that packageBuilder
simply provides value and there's no possible way it could make any test fail. That's a stub. Even though it might seem more blurry, packageService
is stub too. It provides a value (what we do with the value is irrelevant from stub's point of view). Of course, later we'll use that value to test whether exception is thrown, but it's still all within our control (as in, we tell stub exactly what to do and forget about it - it should have no further influence on test).
It gets different with packageDistributor
. Even if it provides any value, it's not consumed. Yet the call to Send
seems to be pretty important part of our implementation and we'll most likely want to verify it is called.
At this point we should get to a conclusion that packageDistributor
is a mock. We'll have a dedicated unit test asserting that Send
method was called and if for some reasons it wasn't - we want to know that, as it's important part of the entire process. Other dependencies are stubs as all they do is provide values to other, perhaps more relevant pieces of code.
Stub being stub, could be just as well replaced with constant value in naive implementation:
var contents = "Important package";
var package = "<package>Important package</package>";
this.packageDistributor.Send(package);
This is essentially what mocking frameworks do with stubs - instruct them to return configurable/explicit value. Old-school, hand-rolled stubs often do just that - return constant value.
Obviously, such code doesn't make much sense, but anyone who ever done TDD surely seen bunch of such naive implementations at the early stage of class development. Iterative development that results from TDD will often help identify roles of your class' dependencies.
At the beginning of this post I mentioned that fake is just a generic term. Given that mock can also serve as stub (especially when modern mocking frameworks are concerned), to avoid confusion it's good idea to call such object a fake. Nowadays, you can see this trend growing - original mock - stub distinction is slowly becoming a thing of the past and more universal names are used. For example: