2013-08-24 34 views
0

当我试图测试一个ASP.Net MVC控制器/动作时,我很难在单元测试模式中缠绕我的头。如何在操作中对具有私有方法的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); 

,但我不知道在哪里可以从这里走。我有很多看起来像这样的代码。我做错了什么,或者有没有真正的方法来测试?

感谢您的任何帮助或指针。

+0

挂钩一个调试器,看看发生了什么。 –

+0

@DanielMann我已经这样做了。 'dt'为空,因为'GetPersonInfo()'方法正在使用模拟数据访问块。在下面的回答中,@sri指出了我的正确方向。我添加了一个简短的问题,我希望他能够清理,然后接受他的答案。 –

回答

1

是您的CommonDomainService.PersonService是某种web服务托管在您的web应用程序中,当您运行测试时,您的web应用程序将不会运行,服务将无法访问。 理想情况下,您的控制器对您在私有方法中创建的CommonDomainService.PersonService具有依赖关系,而应该将其注入到Controller中(与您的DataAccess块一样),并在您的测试方法中对其进行模拟。

+0

感谢您的建议。我改变了私人PersonViewModel GetPersonViewModel(PersonRequestViewModel personRequest)'接受一个I​​CommonDomainService。在我的测试中,我添加了'mockCommonDomainService.Setup(x => x.GetPeronInfo(It.IsAny ()))。返回(new DataTable());'一切正常。但是,如果我新建一个DataTable(),为它分配列并添加一行;然后在模拟设置的'.Returns()'中使用这个DataTable,当测试DataTable时它仍然是'null'。有什么想法吗? –

+0

我没有看到新方法的任何问题,您能否发布新代码? –

+0

你说得对。一切正常。我在测试的早期版本中有一个错误。非常感谢。通过这个练习,我学到了很多东西。 –

0

write private readonly IDataAccessBlock _dab;而不是私人的IDataAccessBlock _dab;

+1

在这种情况下会有什么帮助? –

相关问题