Asp.net mvc 3 MVC应用程序中的详细单元测试方法出错
我正在开发一个MVC应用程序,并试图在其中创建一个单元测试 我已经编写了如下所示的单元测试Asp.net mvc 3 MVC应用程序中的详细单元测试方法出错,asp.net-mvc-3,unit-testing,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 =
[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);
}
当我尝试运行单元测试时,它在最后一行的测试方法中返回一个错误:
对象引用未设置为对象的实例
由于我是单元测试新手,我不知道如何为索引、创建、编辑、详细信息和删除方法编写测试方法,在哪里可以找到它?在代码中有许多地方可能会出现NRE。例如,控制器操作中使用的
db
变量可能为空。确保它已初始化。在单元测试中,您还有以下调用var Comp=(Company)result.ViewData.Model代码>。如果数据库中没有id=97的公司,则该值可能为空。然后尝试比较名称Assert.AreEqual(“TName”,Comp.name)代码>。但如果Comp
为空,则会引发异常。此外,在单元测试中,您使用了一些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);
}
[TestMethod]
公开作废公司_详情2()
{
//安排
var repository=Substitute.For();
var-id=97;
var公司=新公司();
GetCompanyById(id).Returns(company);
var sut=新公司控制器(存储库);
//表演
var实际值=汇总明细(id);
//断言
IsInstanceOfType(实际的,typeof(ViewResult));
var viewResult=(viewResult)实际值;
arenequal(company,viewResult.Model);
}
如其他人所示,为接口编写代码是一种很好的做法。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
}
[TestMethod]
SomeMethod()
{
//这将为您的接口创建一个假/模拟,以便您仍然可以调用func。
//但不是真的。
Mock mockedRepository=new Mock();
//在这里,我们正在进行假呼叫,但仍然返回将为我们提供输出。
mockedRepository.SetUp(x=>x.Details())。返回(公司对象);
var result=controller.Action()作为ViewResult;
//断言
}
有些人可能会说,但我没有测试详细的方法,因为您将编写另一个单元测试等等。谢谢Darin,但是我完全不知道ICompaniesRepository和moq的事情…它们是什么?如果我在我的当前代码中得到我必须做的更改会很好。你希望我在不显示当前代码的情况下告诉你当前代码的更改吗?您所展示的只是代码的一小部分。其思想是使用一个接口来抽象所有数据访问操作,这样控制器就不会与特定的数据访问提供程序紧密耦合。如果您不知道什么是接口,那么我强烈建议您在进入ASP.NET MVC之前,先阅读.NET/C中的一些基本入门教程。