2010-04-08 72 views
4

我只是新单元测试和ASP.NET MVC。我一直在试图用Steve Sanderson的“Pro ASP.NET MVC框架”让我的头脑同时进入。在这本书中有这样一段代码:Moq中的Verify()有多可靠?

public class AdminController : Controller 
{ 
... 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Edit(Product product, HttpPostedFileBase image) 
    { 
     ... 
     productsRepository.SaveProduct(product); 

     TempData["message"] = product.Name + " has been saved."; 
     return RedirectToAction("Index"); 
    } 
} 

那他测试,像这样:

[Test] 
public void Edit_Action_Saves_Product_To_Repository_And_Redirects_To_Index() 
{ 
    // Arrange 
    AdminController controller = new AdminController(mockRepos.Object); 

    Product newProduct = new Product(); 

    // Act 
    var result = (RedirectToRouteResult)controller.Edit(newProduct, null); 

    // Assert: Saved product to repository and redirected 
    mockRepos.Verify(x => x.SaveProduct(newProduct)); 
    Assert.AreEqual("Index", result.RouteValues["action"]); 
} 

测试通过。

因此,我故意通过添加“productsRepository.DeleteProduct(product);”来破坏代码。之后的“SaveProduct(产品)”;“如:

  ... 
     productsRepository.SaveProduct(product); 
     productsRepository.DeleteProduct(product); 
      ... 

测试通过(即纵容灾难性[催眠+智能感知诱导的错字:))

可这测试写入更好?或者有什么我应该知道的?非常感谢。

回答

7

我想你可能会误解.Verify()方法的用途。

它验证给定的方法是否以期望的值被调用。

Steve在说'注意它是如何使用Moqs .Verify()方法确保AdminController确实使用正确的参数调用DeleteProduct()。'

所以在你的情况下,测试通过,因为它只是验证呼叫而不是功能。

正如TDD正在书的过程中,加入的过程中,随后

productsRepository.DeleteProduct(product); 

应首先被添加到测试

// Assert: Saved product to repository, then deleted and redirected 
mockRepos.Verify(x => x.SaveProduct(newProduct)) 
mockRepos.Verify(x => x.DeleteProduct(newProduct)); 
Assert.AreEqual("Index", result.RouteValues["action"]); 

,然后添加到代码

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Edit(Product product, HttpPostedFileBase image) 
{ 

    ... 
productsRepository.SaveProduct(product); 
productsRepository.DeleteProduct(product); 
    ... 
0

这个想法是“编写最简单的代码”。这有助于避免在增量计数器操作中执行诸如从磁盘删除文件等蠢事。显然,不删除文件更简单。

2

您的代码故意“损坏”不会中断测试,因为您在Verify()SaveProduct()之后完成了测试。我一直发现Moq的Verify()非常可靠。

一些伪代码,一个更强大的测试可能是有你的资料库实现一个接口,并有一个简单的内存可测试版本

// Arrange 

var repo = SetupTestableRepository() 
var product = CreateProduct(productId) 

// Act 
repo.SaveProduct(product) 

// Assert 
Assert.IsNotNull(repo.Fetch(productId)) 

善良,

4

正如其他人所说,测试通过,因为你的断言:

mockRepos.Verify(x => x.SaveProduct(newProduct)); 

已完成。你的代码做了调用SaveProduct方法。

Mock.Verify()方法无法验证其他方法不是调用,这是您期望它执行的操作。

如果您担心会发生奇怪的事情(比如在Save()之后调用Delete()并希望通过测试阻止它),那么您也必须为该条件添加Verify() 。例如:

mockRepos.Verify(x => x.DeleteProduct(newProduct), Times.Never()); 
+0

是的。一些模拟框架支持严格的模拟,这将验证模拟上没有其他方法被调用,但这些方法往往导致脆弱的测试。 – TrueWill 2010-04-09 22:19:50