Moq中Verify()的可靠性如何?

时间:2010-04-08 08:35:52

标签: asp.net-mvc unit-testing mocking moq verify

我只是单元测试和ASP.NET MVC的新手。我一直在尝试使用Steve Sanderson的“Pro ASP.NET MVC框架”。书中有这段代码:

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(product);”之后如:

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

测试通行证(即宽恕一种灾难性的[催眠+智能感知 - 诱导的错字:))

这个测试能写得更好吗?或者我应该知道什么?非常感谢。

4 个答案:

答案 0 :(得分:7)

我认为你可能误解了.Verify()方法的目的。

它验证使用期望值调用给定方法。

在本书的第187页,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);
    ...

答案 1 :(得分:4)

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

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

实现了。您的代码 调用了SaveProduct方法。

Mock.Verify()方法无法验证是否有其他方法未被调用,这正是您期望它做的。

如果你担心发生了一些奇怪的事情(比如在Save()之后调用Delete())并希望通过测试来阻止它,你也必须为该条件添加一个Verify()。类似的东西:

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

答案 2 :(得分:2)

您有意“破坏”代码并不会破坏测试,因为您在Verify()SaveProduct()之后已经完成了测试。我一直认为Moq的Verify()非常可靠。

更强大的测试的一些伪代码可能是让您的存储库实现一个接口并具有一个简单的内存可测试版本

// Arrange

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

// Act 
repo.SaveProduct(product)

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

善,

答案 3 :(得分:0)

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