用Moq框架模拟类

时间:2018-07-31 16:25:51

标签: c# unit-testing asp.net-core moq

我正在尝试模拟存储库方法的结果,该方法将返回类对象列表。如果正在检查结果是否包含数据,则API将根据检查结果返回状态代码。能够模拟结果,但是在检查结果包含数据时抛出空引用异常。这是控制器和测试用例的代码。

public IActionResult Get([FromQuery] FilterRequst request)
{
    IEnumerable<Student> result = _repository.GetAll(Mapper.Map<StudentFilter>(request));

    if (result != null && result.Count() > 0)//here throwing null reference exception
    {
        List<StudentModel> model = Fill(result.ToList());
        var response = new StudentListModel()
        {
            TotalRecords = model.Count,
            Items = model
        };
        return new ObjectResult("OK")
        {
            StatusCode = (int?)HttpStatusCode.OK,
            Value = response
        };
    }
    return new ObjectResult("No Content")
    {
        StatusCode = (int?)HttpStatusCode.NoContent,
        Value = "No Content"
    };
}

测试用例:

public void StudentGetAllTestReturnsStudents()
{
    var fakeStudents = new Mock<IEnumerable<Student>>();
    _mockRepository.Setup(x => x.GetAll(It.IsAny<Filter>())).Returns(fakeStudent.Object);
    _studentController = new StudentsController(_mockRepository.Object);
    Mapper.Initialize(cfg =>
    {
        cfg.CreateMap<FilterModel, Filter>();
    });

    // Act
    var actionResult = _studentController.Get(It.IsAny<FilterModel>());
    var result = actionResult as ObjectResult;
    var model = result.Value as StudentListModel;

    // Assert
    Assert.IsNotNull(result);
    Assert.AreEqual(StatusCodes.Status200OK, result.StatusCode);
    Assert.IsNotNull(model);
}

如何模拟IEnumerable<Student>null不能被检查的Count

2 个答案:

答案 0 :(得分:1)

代码无法正常工作的原因有两个。

  1. 您正在嘲笑IEnumerable<>,但没有对其进行设置,以便其方法和属性返回值。您正在调用.Count(),但未指定调用该方法时模拟对象应执行的操作。
  2. 即使您确实设置了IEnumerable<>来返回假值,也无法直接模拟.Count()之类的扩展方法。参见this answer

您不需要模拟IEnumerable。您只需要模拟您的类,并且仅当您想覆盖它们的默认行为时。

答案 1 :(得分:0)

所安排的设置和被测方法的调用未正确完成

public void StudentGetAllTestReturnsStudents() {
    //Arrange
    var fakeStudents = new List<Student>() { //used actual list instead of mock
        new Student() {  }
    };
    _mockRepository
        .Setup(_ => _.GetAll(It.IsAny<StudentFilter>()))
        .Returns(fakeStudents);
    _studentController = new StudentsController(_mockRepository.Object);
    Mapper.Initialize(cfg => {
        cfg.CreateMap<FilterRequst, StudentFilter>();
    });

    // Act
    var actionResult = _studentController.Get(new FilterRequst());//use actual model
    var result = actionResult as ObjectResult;
    var model = result.Value as StudentListModel;

    // Assert
    Assert.IsNotNull(result);
    Assert.AreEqual(StatusCodes.Status200OK, result.StatusCode);
    Assert.IsNotNull(model);
}

仅仅因为您可以模拟对象并不意味着您总是应该如此。如果您可以使用实际对象而不会造成负面影响,请继续进行。您可以嘲笑要更改其行为的东西,例如依赖项。

Student和其他模型应该可以安全地使用其实例,只要它们没有不良行为即可。