public void GetPage_Should_Return_A_Page_from_database_when_cache_is_empty_and_then_caches_it()
{
var cache = new Mock();
var database = new Mock();
IPageRepository pageRepository = new PageRepository(database.Object, cache.Object);
const int pageId = 1;
var page = default(Page);
var samplePage = new Page() { ID = pageId, Title = "Test Page", ...};
database
.Expect(d => d.GetSingle(
DropthingsDataContext.SubsystemEnum.Page,
1, LinqQueries.CompiledQuery_GetPageById))
.Returns(samplePage);
"Given PageRepository and empty cache".Context(() =>
{
// cache is empty
cache.Expect(c => c.Get(It.IsAny())).Returns(default(object));
// It will cache the Page object afte loading from database
cache.Expect(c =>
c.Add(It.Is(cacheKey =>
cacheKey == CacheSetup.CacheKeys.PageId(pageId)),
It.Is(cachePage =>
object.ReferenceEquals(cachePage, samplePage))))
.AtMostOnce().Verifiable();
});
"when GetPageById is called".Do(() =>
page = pageRepository.GetPageById(1));
"it checks in the cache first and finds nothing and then caches it".Assert(() =>
cache.VerifyAll());
"it loads the page from database".Assert(() =>
database.VerifyAll());
"it returns the page as expected".Assert(() =>
{
Assert.Equal(pageId, page.ID);
});
}
单元测试的意义何在?
我觉得写单元测试时,所测试的方法不只是在调用测试方法。单元测试已经确切地知道什么其它的类和方法将被调用。在上面的例子中,是否使用cache或database是在方法中决定的,所以,可以进行逻辑测试。例如,我改变了代码来使用AspectF库。这需要代码变更PageRepository 。更改代码后,我需要确保PageRepository还是按照预期的行为。不管我用什么方法的缓存,它不应该改变缓存行为:检查缓存,以确保所请求的对象是不是已经在缓存中,然后从数据库中加载并缓存它。改变方法GetPageById,实施后AspectF ,如下所示:
public Page GetPageById(int pageId)
{
return AspectF.Define
.Cache(_cacheResolver, CacheSetup.CacheKeys.PageId(pageId))
.Return(() =>
_database.GetSingle(DropthingsDataContext.SubsystemEnum.Page,
pageId, LinqQueries.CompiledQuery_GetPageById).Detach());
}
现在,当我运行单元测试,它表示通过。
它确认行为PageRepository没有改变,尽管它的代码急剧变化。有了正确的单元测试,即使你在代码中改变了,只要你的单元测试全部通过,你的系统是没有问题。接下来让我们来测试,当缓存满了,它正确地从缓存中返回一个对象,而不是不必要的查询数据库。下面的试验将确保:
[Specification]
public void GetPage_Should_Return_A_Page_from_cache_when_it_is_already_cached()
{
var cache = new Mock();
var database = new Mock();
IPageRepository pageRepository = new PageRepository(database.Object, cache.Object);
const int pageId = 1;
var page = default(Page);
var samplePage = new Page() { ID = pageId, Title = "Test Page",
ColumnCount = 3, LayoutType = 3, UserId = Guid.Empty, VersionNo = 1,
PageType = Enumerations.PageTypeEnum.PersonalPage,
CreatedDate = DateTime.Now };
"Given PageRepository and the requested page in cache".Context(() =>
{
cache.Expect(c => c.Get(CacheSetup.CacheKeys.PageId(samplePage.ID)))
.Returns(samplePage);
});
"when GetPageById is called".Do(() =>
page = pageRepository.GetPageById(1));
"it checks in the cache first and finds the object is in cache".Assert(() =>
{
cache.VerifyAll();
});
"it returns the page as expected".Assert(() =>
{
Assert.Equal(pageId, page.ID);
原文转自:http://www.codeproject.com/Articles/44276/Unit-Testing-and-Integration-Testing-in-Business-A