Wednesday, March 5, 2014

What, when, how - dummy, fake, stub and mocks

Test doubles are objects that replace the dependent-on-component (DOC) in a test context so that the system under test gets an API as the real DOC and can perform activities against the API thinking that it is a real one!!!
There are different variations in the type of test doubles depending on the intent and context of usage. Ref: Test double patterns at XUnitPatterns.com.
In this post I’ll demonstrate the usage of the four main test doubles (Dummy, Fake, Stub and Mock) in the context of Microsoft Fakes and scenarios on how they can be implemented in your projects to enhance code coverage. All the definitions for the patterns are copied from Gerard Meszaros XUnitPatterns catalog.

Dummy: A dummy is an object that is passed as a method argument or used as an attribute in a test context but never actually used. Usually they are just used to fill parameter lists.

var dummyCustomer = new StubCustomer();
var sut = new Invoice(dummyCustomer);
var book = new Product("XUnitPatterns");
sut.AddItemQuantity(book, 5);
var actual = sut.GetAllLineItems();
Assert.IsTrue(actual.Count() == 1);

Fake: A Fake object actually have working implementations, but usually take some shortcut which makes them not suitable for production. The fake object need not have any of the "-ilities" that the real DOC needs to have (such as scalability); it need only provide the equivalent services to the SUT so that the SUT isn't aware it isn't using the real DOC.

var dummyCustomer = new StubCustomer();
var sut = new Invoice(dummyCustomer);

var logger = new FakeLogger();
sut.Logger = logger;

var book = new Product("XUnitPatterns");
sut.AddItemQuantity(book, 0); //Throws exception if quantity is less than 0 and logs the error. Should use the FakeLogger to write the message to log.

Stub: Stubs can replace a real object with a test-specific object that feeds the desired indirect inputs into the system under test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.

var dummyCustomer = new StubCustomer();
var sut = new Invoice(dummyCustomer);
var validator = new StubIProductValidator()
{
    IsValidProduct = (p) => { return true; }
};
sut.Validator = validator;
var book = new Product("XUnitPatterns");
sut.AddItemQuantity(book, 2);
var actual = sut.GetAllLineItems();
Assert.IsTrue(actual.Count() == 1);

Mock: A mock replaces an object the system under test (SUT) depends on with a test-specific object that verifies it is being used correctly by the SUT. Mocks insist upon behavior verification. The other doubles can, and usually do, use state verification. Developers perform assertions on mock objects to ensure that the behavior expectations were met during test execution

var dummyCustomer = new StubCustomer();
var sut = new Invoice(dummyCustomer);
var observer = new StubObserver();

var validator = new StubIProductValidator()
{
    InstanceObserver = observer,
    IsValidProduct = (p) => { return true; }
};

sut.Validator = validator;
var book = new Product("XUnitPatterns");
sut.AddItemQuantity(book, 2);
           
Assert.IsTrue(observer.GetCalls().Any(call => call.StubbedMethod.Name == "IsValid"));




No comments: