简体   繁体   中英

Mocking the class with Moq framework

I am trying to mock the result of a repository method which will return me a list of class objects. Am having a check if the result contains data then the API will return the status code depending on the check. Am able to mock the result but it throwing null reference exception while it checking the results contains data. Here is the code for controller and test case.

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

Testcase:

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

How can I mock the IEnumerable<Student> which can be checked for not null and Count ?

There are two reasons why your code is not working.

  1. You are mocking IEnumerable<> but not setting it up so that its methods and properties return values. You are calling .Count() but not specifying what the mocked object should do when that method is called.
  2. Even if you did set up IEnumerable<> to return fake values, you cannot directly mock extension methods such as .Count() . See this answer .

You do not need to mock IEnumerable . You only need to mock your classes, and only when you want to override their default behavior.

The arranged setup and the invocation of the method under test was not done correctly

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

Just because you can mock objects does not mean that you always should. If you can use an actual object without causing negative side effects then go ahead. You mock the things you want to change the behavior of, like dependencies.

Student and other models should be safe to use their instances provided they have no unwanted behavior.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM