0

我正在开发一个 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);
}

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

你调用的对象是空的。

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

4

2 回答 2

1

There are many places where a NRE could occur in your code. For example the db variable that is used in your controller action might be null. Make sure that it is initialized. Also in your unit test you have the following call var Comp = (Company)result.ViewData.Model;. This could be null if there's no Company with id = 97 in your database. And then you attempt to compare the name Assert.AreEqual("TName", Comp.Name);. But if Comp is null this will throw an exception. Also in your unit test you are using some oCompanyController variable which is unclear where it got initialized.

The correct way to unit test some code is to unit test it in isolation. This means that your code should be written with abstractions in mind. It should not depend on actual implementations. It is unclear what the db variable is in your controller but it should be of some interface type (or abstract class) that you could mock in your unit test. This way you will achieve unit testing in isolation of the different layers. In this example you are unit testing a controller action, so the code in this controller should not depend on concrete classes.

Let's have an example of how your controller code might look like:

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);
    }
}

Now you could use a mocking framework such as Moq, NSubstitute or Rhino.Mocks to mock the repository in your unit test and be able to define expectations. For example with 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);

}
于 2013-06-08T10:30:07.633 回答
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
}

有些人可能会争辩说,但我没有测试 Details 方法,因为你将编写另一个单元测试等等。

于 2013-08-15T12:02:43.283 回答