15. {
16. return null;
17. }
18.
19. public IEnumerable GetProducts()
20. {
21. throw new NotImplementedException();
22. }
23.}
在這個例子中,我們為每個測試都做了一個獨立的Repository。但我們也可在一個Repository上添加額外的邏輯,例如:
01.public class StubProductRepository : IProductRepository
02.{
03. public Product GetByID(string id)
04. {
05. if (id == "spr-product")
06. {
07. return new Product()
08. {
09. ID = "spr-product",
10. Name = "Nice Product"
11. };
12. }
13.
14. return null;
15. }
16.
17. public IEnumerable GetProducts()
18. {
19. throw new NotImplementedException();
20. }
21.}
在第一種方法里,我們寫了兩個不同的IProductRepository模擬方法,而在第二種方法里,我們的邏輯變得有些復雜。如果我們在這些邏輯中犯了錯,那我們的測試就沒法得到正確的結果,這又為我們的調試增加了額外的負擔,我們需要找到是業務代碼出來錯還是測試代碼不正確。
你也許還會質疑這些模擬代碼中的這個沒有任何用處的 GetProducts()方法,它是干什么的?因為IProductRepository接口里有這個方法,我們不得不加入這個方法以讓程序能編譯通過——盡管在我們的測試中這個方法根本不是我們考慮到對象。
使用這樣的測試方法,我們不得不寫出大量的臨時模擬類,這無疑會讓我們在維護時愈加頭痛。這種時候,使用一個模擬框架,比如JustMock,將會節省我們大量的工作。
讓我們重新看一下之前的這個測試例子,這次我們將使用一個模擬框架:
01.[TestMethod]
02.public void GetProductWithValidIDReturnsProduct()
03.{
04. // Arrange
05. IProductRepository productRepository = Mock.Create();
06. Mock.Arrange(() => productRepository.GetByID("spr-product")).Returns(new Product());
07. ProductService productService = new ProductService(productRepository);
08.
09. // Act
10. Product product = productService.GetByID("spr-product");
11.
12. // Assert
13. Assert.IsNotNull(product);
14.}
15.
16.[TestMethod]
17.public void GetProductWithInValidIDThrowsException()
18.{
19. // Arrange
20. IProductRepository productRepository = Mock.Create();
21. ProductService productService = new ProductService(productRepository);
22.
23. // Act & Assert
24. Assert.Throws(() => productService.GetByID("invalid-id"));
25.}
有沒有注意到我們寫的代碼的減少量?在這個例子中代碼量減少49%,更準確的說,使用模擬框架測試時代碼是28行,而沒有使用時是57行。我們還看到了整個測試方法變得可讀性更強了!
2、測試代碼組織的太松散
模擬框架讓我們在模擬測試中的生成某個依賴類的工作變得非常簡單,但有時候太輕易實現也容易產生壞處。為了說明這個觀點,請觀察下面兩個單元測試,看看那一個容易理解。這兩個測試程序是測試一個相同的功能:
Test #1
01.TestMethod]
02.public void InitializeWithValidProductIDReturnsView()
03.{
04. // Arrange
05. IProductView productView = Mock.Create();
06. Mock.Arrange(() => productView.ProductID).Returns("spr-product");
07.
08. IProductService productService = Mock.Create();
09. Mock.Arrange(() => productService.GetByID("spr-product")).Returns(new Product()).OccursOnce();
10.
11. INavigationService navigationService = Mock.Create();
12. Mock.Arrange(() => navigationService.GoTo("/not-found"));
13.
14. IBasketService basketService = Mock.Create();
15. Mock.Arrange(() => basketService.ProductExists("spr-product")).Returns(true);
16.
17. var productPresenter = new ProductPresenter(
原文轉自:http://www.vaikan.com/top-5-tdd-mistakes/