MVC App中的详细信息方法中的单元测试出错

时间:2013-06-08 10:26:22

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

我正在开发一个MVC应用程序,并试图在其中创建一个单元测试。

我已经编写了单元测试,如下所示。

   [TestMethod]
        public void Company_Details2()
        {
            Company oCompany = new Company();
            var result = oCompanyController.Details(97) as ViewResult;
            var Comp = (Company)result.ViewData.Model;
            Assert.AreEqual("TName", Comp.Name);

        }

和控制器如下:

[SessionFilterAction]
public ViewResult Details(int id)
{
    Company company = db.Companies.Find(id);
    return View(company);
}

当我尝试运行单元测试时,它会在最后一行的测试方法中返回错误:

  

对象引用未设置为对象的实例。

由于我不熟悉单元测试,我不知道如何编写索引,创建,编辑,详细信息和删除方法的测试方法,我在哪里可以找到它?

2 个答案:

答案 0 :(得分:1)

在您的代码中,有很多地方可能会出现NRE。例如,控制器操作中使用的db变量可能为null。确保它已初始化。同样在您的单元测试中,您可以拨打以下电话var Comp = (Company)result.ViewData.Model;。如果您的数据库中没有id = 97的公司,则此值可以为null。然后您尝试比较名称Assert.AreEqual("TName", Comp.Name);。但是如果Comp为null,则会抛出异常。同样在您的单元测试中,您使用的是一些oCompanyController变量,该变量在初始化的位置不清楚。

单元测试某些代码的正确方法是单独对其进行单元测试。这意味着您的代码应该考虑抽象。它不应该依赖于实际的实现。目前还不清楚控制器中的db变量是什么,但它应该是您可以在单元测试中模拟的某种接口类型(或抽象类)。这样,您将实现单独测试,隔离不同的层。在这个例子中,你是单元测试一个控制器动作,所以这个控制器中的代码不应该依赖于具体的类。

让我们举一个控制器代码的示例:

public class CompaniesController: Controller
{
    public readonly ICompaniesRepository repository;
    public CompaniesController(ICompaniesRepository repository)
    {
        this.repository = repository;
    }

    [SessionFilterAction]
    public ViewResult Details(int id)
    {
        Company company = this.repository.GetCompanyById(id);
        return View(company);
    }
}

现在,您可以使用模拟框架(如Moq,NSubstitute或Rhino.Mocks)来模拟单元测试中的存储库,并能够定义期望。例如,使用NSubstitute:

[TestMethod]
public void Company_Details2()
{
    // arrange
    var repository = Substitute.For<ICompaniesRepository>();
    var id = 97;
    var company = new Company();
    repository.GetCompanyById(id).Returns(company);
    var sut = new CompaniesController(repository);

    // act
    var actual = sut.Details(id);

    // assert
    Assert.IsInstanceOfType(actual, typeof(ViewResult));
    var viewResult = (ViewResult)actual;
    Assert.AreEqual(company, viewResult.Model);

}

答案 1 :(得分:0)

正如其他人所表明的那样,对接口进行编码是一种很好的做法。 Moq是一个框架,可以帮助您对所需功能进行虚假调用,并且学习起来非常简单。现在我假设您正在呼叫,IRepository.Detials(),现在,

[TestMethod]
SomeMethod()
{
 // This will create a fake/mock for your interface so that you can still call func. 
 // but not actual one.
  Mock<IRepository> mockedRepository= new Mock<IRepository>();

 // Here, we are making fake call but still Returns will give us the output.
  mockedRepository.SetUp(x=>x.Details()).Returns(Company Object);
  var result=controller.Action() as ViewResult;
  // Assert
}

有些人可能会说,但我没有测试详细信息方法,因为你会编写另一个单元测试等等。