测试MVC控制器出现故障空引用异常 [英] Testing a MVC Controller fails with NULL reference exception

查看:244
本文介绍了测试MVC控制器出现故障空引用异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是我想测试设置。

控制器:

public ActionResult UpsertStudent(StudentModel studentModel)
{
    try
    {

        if (!CheckStudentUpdateForEdit(studentModel))
        {

            return Json(new { result = STUDENT_EXISTS });

        }
    // remaining code removed for brevity 
}

private bool CheckStudentUpdateForEdit(StudentModel studentModel)
{
    var returnVal = true;

    var existingStudent = _updateStudentManager.GetStudentInfo(studentModel.Id);

    if (existingStudent.StudentType == "Day Scholar")
    {
        returnVal = true;
    }
    else
    {
        returnVal = false;
    }

    return returnVal;
}

测试方法:

public void AllowStudentUpdates_Success()
{
    var studentModel = new StudentModel()
    {
        StudentName = "Joe",
        Id = "123",
        StudentType = "Day Scholar"
    };

    var studentToAdd = new Student()
    {
        Id = "123",
        Name = "Joe",
        StartDate = DateTime.UtcNow.ToShortDateString(),
        StudentType = "Day Scholar",
        EndDate = "08/10/2016"
    };

    _studentRulesHelper.Setup(x => x.GetStudentRule(studentModel, true)).Returns(studentToAdd);
    _productRulesHelper.Setup(x => x.ReturnStudentRule(studentModel, true)).Returns(studentToAdd);

    var res = _controller.UpsertStudent(studentModel) as JsonResult;
    if (res != null) Assert.AreEqual("{ result = True }", res.Data.ToString());
}

当它击中 UpsertDoc 通话,它关系到控制器的实际调用,并试图执行 CheckStudentUpdateForEdit() GetStudentInfo()试图从DB对象并没有学生与来自的测试方法传递的ID返回一个空的对象。
那么测试失败,空引用除外。

When it hits the UpsertDoc call, it goes to the actual call in the controller and tries to execute CheckStudentUpdateForEdit() the GetStudentInfo() tries to get an object from the db and returns a null object as there is no student with the id that's passed from the test method. The test then fails with Null Reference exception.

现在测试中的系统是不应该打分贝。我不知道这是为什么做其他的方式!

Now the system under test is not supposed to hit the db. I don't know why this is doing the other way!

还有其他人写这个测试也将尝试通过它注定要失败的虚拟对象GetStudentInfo()的测试设置现在的方式。

Anyone else writing this test will also try to pass a dummy object which is bound to fail at GetStudentInfo() the way the test is setup now.

我该怎么办,使这项工作?

What do I do to make this work?

推荐答案

我不知道如果我理解正确的话,你的问题,但看着提供的code片段,该测试将去访问数据库,因为模拟对象和它的期望是没有定义的。

I am not sure if I have understood you problem correctly, but looking at the code snippets provided, the test will go and hit the database, because the mock object and its expectation is not defined.

我就已经实现了这样的解决方案 -

I would have implemented the solution like this -

我想提出一些假设你的 _updateStudentManager 对象是类是做数据库交互的学生 。我会打电话给它说 StudentRepository 。并允许你嘲笑的行为我想使它成为接口驱动。
所以通常我的设置是这样的 -

I am making some assumptions that your _updateStudentManager object is for the class that is doing the DB interaction for Student. I'll call it say StudentRepository. And to allow you to mock the behavior I would make it Interface driven. So typically my setup would look like this -

//Interface
public interface IStudentrepository
{
    StudentModel GetStudentInfo(int studentId);
}

//Class implementing IStudentrepository
public class StudentRepository : IStudentrepository
{
    public StudentModel GetStudentInfo(int studentId)
    {
        //Implementation goes here
    }
}

现在在我的控制器,我会IStudentrepository的实例,可以通过构造函数来注入。

Now in my controller, I would have an instance of IStudentrepository, which can be injected via constructor.

public class StudentController
{
    private readonly IStudentrepository updateStudentManager;
    public StudentController(IStudentrepository updateStudentManager)
    {
        this.updateStudentManager = updateStudentManager;
    }
}
//Rest of the code for controller....

现在在写我的测试,我将创建 IStudentrepository 的模仿对象,定义模拟的期望对象,和创建控制器对象时注入它。事情是这样的。

Now while writing my Test, I will create a mock object of IStudentrepository, define the expectation for the mock object, and inject it when creating the controller object. Something like this.

    [TestMethod]
    public void TestMethod1()
    {
        //--Arrange--
        //Define a mock object for student repository
        var mock = new Mock<IStudentrepository>();

        //Define the expectations of the mock object
        mock.Setup(s => s.GetStudentInfo(It.IsAny<int>()))
            .Returns(new StudentModel {/*return the required object */ });

        //Instantiate controller and inject the mock object
        StudentController _controller = new StudentController(mock.Object);

        //--Act--
        var res = _controller.UpsertStudent(studentModel) as JsonResult;


        //--Assert--
        if (res != null) Assert.AreEqual("{ result = True }", res.Data.ToString());

    }

现在,当您的测试方法调用 GetStudentInfo 方法,而不是击中分贝,就会在模拟对象设置返回值。

Now when your test method calls the GetStudentInfo method, instead of hitting the db, it will return the value as set in mock object.

这仅仅是一个高层次的实现,当然你可以修改它根据您的设​​计。希望它能帮助

This is just a high level implementation, and of course you can modify it as per your design. Hope it helps

这篇关于测试MVC控制器出现故障空引用异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆