【问题标题】:Unit Testing MVC Controllers单元测试 MVC 控制器
【发布时间】:2011-12-19 14:38:47
【问题描述】:

我的 ASP.NET MVC 应用程序中的控制器根据几个相当直接的规则预填充视图显示的表单数据。

在我的单元测试中涵盖这似乎是一件好事。但我能看到的唯一方法是验证表单中是否放置了正确的数据,那就是以一种不自然的方式从控制器中提取逻辑。

有人可以建议解决这个问题的方法吗?

我发现的所有关于单元测试控制器的示例似乎都很琐碎,例如验证它是否返回了预期的视图类型。我什至不确定我是否看到了其中的价值。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 unit-testing


    【解决方案1】:

    您可以通过将返回的对象转换为适当的类来进行测试,而不是使用它们的基类(默认返回)

    例如,要测试默认的AccountController,你会这样:

    var controller = new AccountController();
    var result = controller.LogOn() as ViewResult;
    var model = result.Model as LogOnModel;
    
    Assert.IsTrue(model.RememberMe); // assuming you "pre-populated" enabled the checkbox
    

    检查返回的对象是否填充了正确的数据在我看来并不“不自然”,还是您的意思不同?

    【讨论】:

    • 啊...result.Model 看起来很有帮助。
    【解决方案2】:

    我同意测试返回的视图类型有点毫无意义。但是,测试返回的预期“视图”及其正确数据将是一个有效的测试用例 IMO。

    例如,这里是一个编辑控制器的单一编辑测试用例。请注意,此示例使用了 Moq 和 Nunit,但除此之外它相当简单。

    请注意,该 ViewResult 被强制转换为预期的视图模型,然后针对预期的联系人进行断言。

    测试:

    [Test]
    public void Edit_Get_Should_Lookup_Contact_From_Repository_And_Return_Edit_View()
    {
        // arrange
        var _repository = new Mock<IContactRepository>();
    
        var expectedContact = new Contact
        {
            First = "first",
            Last = "last",
            Email = "mail@test.com"
        };
    
        var mockContext = new Mock<ControllerContext>();
        _repository.Setup(x => x.GetById(It.IsAny<int>())).Returns(expectedContact);
    
        var controller = new ContactController(_repository.Object)
        {
            ControllerContext = mockContext.Object
        };
    
        // act
        var result = controller.Edit(1) as ViewResult;
        var resultData = (Contact)result.ViewData.Model;
    
        // assert
        Assert.AreEqual("Edit", result.ViewName);
        Assert.AreEqual(expectedContact.First, resultData.First);
        Assert.AreEqual(expectedContact.Last, resultData.Last);
        Assert.AreEqual(expectedContact.Email, resultData.Email);
    }
    

    控制器:

    [HttpGet]
    public ActionResult Edit(int id)
    {
        var contact = _repository.GetById(id);
    
        return View("Edit", contact);
    }
    

    【讨论】: