4

I'm only new to Unit Testing and ASP.NET MVC. I've been trying to get my head into both using Steve Sanderson's "Pro ASP.NET MVC Framework". In the book there is this piece of code:

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");
    }
}

That he tests like so:

[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"]);
}

THE TEST PASSES.

So I intentionally corrupt the code by adding "productsRepository.DeleteProduct(product);" after the "SaveProduct(product);" as in:

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

THE TEST PASSES.(i.e Condones a calamitous [hypnosis + intellisense]-induced typo :) )

Could this test be written better? Or is there something I should know? Thanks a lot.

4

4 回答 4

7

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

它验证是否使用预期值调用了给定的方法。

在书的第 187 页,史蒂夫说“注意它如何使用 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);
    ...
于 2010-04-08T10:17:34.473 回答
4

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

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

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

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

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

mockRepos.Verify(x => x.DeleteProduct(newProduct), Times.Never());
于 2010-04-08T15:20:53.970 回答
2

您故意“破坏”代码不会破坏测试,因为您在Verify()调用SaveProduct(). 我一直发现起订量Verify()非常可靠。

一些用于更健壮测试的伪代码可能是让您的存储库实现一个接口并拥有一个简单的内存可测试版本

// Arrange

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

// Act 
repo.SaveProduct(product)

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

善良,

于 2010-04-08T08:51:18.477 回答
0

这个想法是“编写最简单的有效代码”。这可以帮助您避免做一些愚蠢的事情,例如在增量计数器操作中从磁盘中删除文件。显然,不删除文件更简单。

于 2010-04-08T08:43:21.753 回答