【问题标题】:How to unit test ASP.Net MVC controller that has private methods in the action?如何对操作中具有私有方法的 ASP.Net MVC 控制器进行单元测试?
【发布时间】:2013-08-24 00:39:30
【问题描述】:

在尝试测试 ASP.Net MVC 控制器/动作时,我很难将自己的头脑围绕在单元测试模式上。

使用以下代码,我正在尝试为ShowPerson() 方法编写测试:

public class PersonController : Controller
{
    private IDataAccessBlock _dab;

    public PersonController()
        : this(new DataAccessBlock())
    { }

    public PersonController(IDataAccessBlock dab)
    {
        _dab = dab;
    }

    public ActionResult ShowPerson(PersonRequestViewModel personRequest)
    {
        var person = GetPersonViewModel(personRequest);
        return View("Person", person);
    }

    private PersonViewModel GetPersonViewModel(PersonRequestViewModel personRequest)
    {
        var personService = new CommonDomainService.PersonService(_dab);
        var dt = personService.GetPersonInfo(personRequest.Id);
        var person = new PersonViewModel();

        if (dt.Rows.Count == 1)
        {
            person.FirstName = dt.Rows[0]r["FIRSTNAME"]);
            person.LastName = dt.Rows[0]["LASTNAME"];
        }
        return person;
    }
}

我正在使用的测试(使用 nUnit 和 Moq):

[Test]
public void ShowPerson_Action_Should_Return_Person_View()
{
    // Arrange
    string expected = "Person";
    Mock<PersonRequestViewModel> personRequestViewModelMock = new Mock<PersonRequestViewModel>();
    personRequestViewModelMock.SetupProperty(f => f.Id, 123456);

    Mock<IDataAccessBlock> mockDab = new Mock<IDataAccessBlock>();
    PersonController personController = new PersonController(mockDab.Object);

    // Act
    ViewResult result = personController.ShowPerson(personRequestViewModelMock.Object) as ViewResult;

    // Assert
    personRequestViewModelMock.Verify();
    result.Should().Not.Be.Null();
    if (result != null) Assert.AreEqual(expected, result.ViewName, "Unexpected view name");
}

一切似乎都很好,直到遇到if (dt.Rows.Count == 1) 行。我得到一个“对象引用未设置为对象的实例。”

我认为以下两行的编写方式一定有些古怪:

var personService = new CommonDomainService.PersonService(_dab);
var dt = personService.GetPersonInfo(personRequest.Id);

但我不确定从这里去哪里。我有很多看起来像这样的代码。我做错了什么,还是有实际的测试方法?

感谢任何帮助或指点。

【问题讨论】:

  • 挂一个调试器看看发生了什么。
  • @DanielMann 我已经这样做了。 dt 为空,因为 GetPersonInfo() 方法正在使用模拟数据访问块。在下面的答案中,@sri 为我指明了正确的方向。我添加了一个简短的问题,希望他能澄清并接受他的回答。

标签: c# asp.net unit-testing nunit moq


【解决方案1】:

您的 CommonDomainService.PersonService 是托管在您的 Web 应用程序中的某种 Web 服务,当您运行测试时,您的 Web 应用程序将不会运行并且服务将无法访问。 理想情况下,您的控制器依赖于您在私有方法中创建的 CommonDomainService.PersonService,而不是将其注入控制器(就像您执行 DataAccess 块一样),并在您的测试方法中模拟它。

【讨论】:

  • 感谢您的建议。我更改了private PersonViewModel GetPersonViewModel(PersonRequestViewModel personRequest) 以接受 ICommonDomainService。在我的测试中,我添加了mockCommonDomainService.Setup(x =&gt; x.GetPeronInfo(It.IsAny&lt;int&gt;())).Returns(new DataTable());,一切正常。但是,如果我new 了一个 DataTable(),则为其分配列并添加一行;然后在模拟设置的.Returns() 中使用这个DataTable,在测试DataTable 时它仍然是null。有什么想法吗?
  • 我没有发现新方法有任何问题,您能发布新代码吗?
  • 你是对的。一切正常。我在测试的前一行中有一个错误。非常感谢。通过这次练习,我学到了很多东西。
【解决方案2】:

写私有的只读 IDataAccessBlock _dab;而不是私有的 IDataAccessBlock _dab;

【讨论】:

  • 在这种情况下会有什么帮助?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多