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!!!
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"));