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