Dummy vs. Stub vs. Spy vs. Fake vs. Mock

 a) Dummy is simple of all. It’s a placeholder required to pass the unit test. Unit in the context (SUT) doesn’t exercise this placeholder. Dummy can be something as simple as passing ‘null’ or a void implementation with exceptions to ensure it’s never leveraged.

[TestMethod]
public void PlayerRollDieWithMaxFaceValue()
{
var dummyBoard = new Mock<IBoard>();
var player = new Player(dummyBoard.Object, new Die() ); //null too would have been just fine
player.RollDie();
Assert.AreEqual(6, player.UnitsToMove);
}

While the above test would work just fine, it won’t throw any exceptions if RollDie implementation is invoking Board Object. To ensure that Board object isn’t exercised at  all you can leverage strict mock. Strict Mock with throw an exception if no expectation is set for member.

[TestMethod]
public void PlayerRollDieWithMaxFaceValueStrictTest()
{
var dummyBoard = new Mock<IBoard>(MockBehavior.Strict); //Ensure Board class is never invoked
var player = new Player( dummyBoard.Object, new Die() );
player.RollDie();
Assert.AreEqual( 6, player.UnitsToMove );
}

b) Fake is used to simplify a dependency so that unit test can pass easily. There is very thin line between Fake and Stub which is best described here as – “a Test Stub acts as a control point to inject indirect inputs into the SUT the Fake Object does not. It merely provides a way for the interactions to occur in a self-consistent manner. These interactions (between the SUT and the Fake Object) will typically be many and the values passed in as arguments of earlier method calls will often be returned as results of later method calls“. A common place where you would use fake is database access. Below sample shows the same by creating a FakeProductRepository instead of using live database.

public interface IProductRepository
{
void AddProduct(IProduct product);
IProduct GetProduct(int productId);
}

public class FakeProductRepository : IProductRepository
{
List<IProduct>
_products = new List<IProduct>();
public void AddProduct(IProduct product)
{
//...
}
public IProduct GetProduct(int productId)
{
//...
}
}

[TestMethod]
public void BillingManagerCalcuateTax()
{
var fakeProductRepository = new FakeProductRepository();
BillingManager billingManager = new BillingManager(fakeProductRepository);
//...
}

Fakes can be also be implemented by moq using callbacks.

c) Stub is used to provide indirect inputs to the SUT coming from its collaborators / dependencies. These inputs could be in form of objects, exceptions or primitive values. Unlike Fake, stubs are exercised by SUT. Going back to the Die example, we can use a Stub to return a fixed face value. This could simply our tests by taking out the randomness associated with rolling a Die.

[TestMethod]
public void PlayerRollDieWithMaxFaceValue()
{
var stubDie = new Mock<IDie>();
stubDie.Setup(d => d.GetFaceValue()).Returns(6).Verifiable();
IDie die = stubDie.Object;
Assert.AreEqual(6, die.GetFaceValue()); //Excercise the return value
}

d) Mock – Like Indirect Inputs that flow back to SUT from its collaborators, there are also Indirect Outputs. Indirect outputs are tricky to test as they don’t return to SUT and are encapsulated by collaborator. Hence it becomes quite difficult to assert on them from a SUT standpoint. This is where behavior verification kicks in. Using behavior verification we can set expectations for SUT to exhibit the right behavior during its interactions with collaborators. Classic example of this is logging. When a SUT invokes logger it might quite difficult for us to assert on the actual log store (file, database, etc.). But what we can do is assert that logger is invoked by SUT. Below is an example that shows a typical mock in action

[TestMethod]
public void ModuleThrowExceptionInvokesLogger()
{
var mock = new Mock<ILogger>();
Module module = new Module();
ILogger logger = mock.Object;
module.SetLogger(logger);
module.ThrowException("Catch me if you can");
mock.Verify( m => m.Log( "Catch me if you can" ) );
}

e) Spy – Spy is a variation of behavior verification. Instead of setting up behavior expectations, Spy records calls made to the collaborator. SUT then can later assert the recordings of Spy. Below is variation of Logger shown for Mock. Focus on this test is to count the number of times Log is invoked on Logger. It’s doesn’t care about the inputs passed to Log, it just records the Log calls and asserts them. Complex Spy objects can also leverage callback features of moq framework.

[TestMethod]
public void ModuleThrowExceptionInvokesLoggerOnlyOnce()
{
var spyLogger = new Mock<ILogger>();
Module module = new Module();
ILogger logger = spyLogger.Object;
module.SetLogger( logger );
module.ThrowException( "Catch me if you can" );
module.ThrowException( "Catch me if you can" );
spyLogger.Verify( m => m.Log( It.IsAny<string>()), Times.Exactly(2) );
}

The OCR Service to extract the Text Data

Optical character recognition, or OCR, is a key tool for people who want to build or collect text data. OCR uses machine learning to extract...