To illustrate I will use a
SqlStatementBuilder
class that depends on an instance of IPersistable
and an instance of IWhereBuilder
. SqlStatementBuilder
takes an IPersistable
instance which is an object that exposes a name. SqlStatementBuilder
uses IWhereBuilder
to append a where clause.class SqlStatementBuilder...Testing
public SqlStatementBuilder(IPersistable instance, IWhereBuilder where)
{
this.instance = instance;
this.where = where;
}
public string CreateFindAllStatement()
{
string mask = "select * from {0} {1}";
return string.Format(mask,instance.Name,where.ToString());
}
SqlStatementBuilder
requires you to create instances of both IPersistable
and IWhereBuilder
. However, if concrete implementations are used any changes to Persistable
or WhereBuilder
would cascade and could potentially break SqlStatementBuilder
tests.After deciding to use stubs or mocks the decision becomes which of these two options is the best. Some feel that choosing mock or stub usage is exclusive; however, using both is the superior option. A mixture of both solutions can be used to clearly convey the intended usage of a dependency within the current test.
Using a mock to verify the class under test interacts in an expected manner with a dependency is natural. However, tests should verify behavior of a dependency independently of other dependencies. For all dependencies who's behavior is not currently under test a stub is preferred. By using stubs in this manner you convey the message that only the interaction of the class under test and the mocked dependency is important.
For example, if I were testing the
CreateFindAllStatement
method I would test both that IPersistable.Name
was used as the table name and that IWhereBuilder.ToString()
was appended to the end of the select statement.[TestFixture]Developing tests in this manner will increase the readability due to the conciseness and clear intent. Additionally, changing the interaction between a class under test and a dependency will only break the tests specific to that dependency. The tests become more durable because a stub's default behavior should be to return a default value or do nothing in the case of a void method. Therefore, stubs will not need to be updated based on a behavioral change.
class SqlStatementBuilderTests...
[Test]
public void IPersistableNameIsUsedAsTheTableNameInCreateFindAllStatement()
{
IMock mock = new DynamicMock(typeof(IPersistable));
mock.ExpectAndReturn("Name","Foo");
IPersistable persistable = (IPersistable)mock.MockInstance;
SqlStatementBuilder builder = new SqlStatementBuilder(persistable,new StubWhereBuilder());
Assert.AreEqual("select * from Foo ",builder.CreateFindAllStatement());
mock.Verify();
}
[Test]
public void WhereBuilderToStringIsAppendedToTheEndOfAFindAllStatement()
{
IMock mock = new DynamicMock(typeof(IWhereBuilder));
mock.ExpectAndReturn("ToString","where...");
IWhereBuilder where = (IWhereBuilder)mock.MockInstance;
SqlStatementBuilder builder = new SqlStatementBuilder(new StubPersistable(),where);
Assert.AreEqual("select * from where...",builder.CreateFindAllStatement());
mock.Verify();
}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.