我正在开发一个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);
}
当我尝试运行单元测试时,它会在最后一行的测试方法中返回错误:
对象引用未设置为对象的实例。
由于我不熟悉单元测试,我不知道如何编写索引,创建,编辑,详细信息和删除方法的测试方法,我在哪里可以找到它?
答案 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
}
有些人可能会说,但我没有测试详细信息方法,因为你会编写另一个单元测试等等。