0

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?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
user3625533
  • 339
  • 1
  • 4
  • 20
  • 1
    Typically you would mock the dependencies of your application, not the data. You're testing your assumptions of how the system will work given a particular piece of data. – Kenneth K. Jul 31 '18 at 16:46

2 Answers2

1

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.

Dan Wilson
  • 3,937
  • 2
  • 17
  • 27
  • I tried some samples but didnt worked out for me. Decided to use the real objects by creating them manually. But i still not convinced using the real objects while testing. – user3625533 Jul 31 '18 at 17:44
  • Testing real objects is always more meaningful than testing mocks. Mocks are most useful in situations where you want to avoid IO calls and isloate application logic. – Dan Wilson Jul 31 '18 at 17:53
0

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.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • why to create a real object for testing? we can mock the objects using the framework that we are using. – user3625533 Jul 31 '18 at 16:37
  • 1
    Just because you can does not mean that you 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. – Nkosi Jul 31 '18 at 16:38