Search code examples
c#asp.net-coreasp.net-core-webapimoqxunit

How to test async Task<IActionResult> returning IEnumerable<model> using moq in xunit?


I want to test GetMoviesAsync of my Controller. I don't know where I am doing wrong in my Moq setup. I am getting 0 item from GetMoviesAsync.

What am I doing wrong?

// Api-Controller:

   public interface ICommand
   {
        Task<IEnumerable<Movie>> GetMoviesAsync();
   }

   public class SampleController : ControllerBase
    {
        private readonly ICommand movieCommand;

        public SampleController(ICommand command)
        {
            movieCommand = command;
        }

        [HttpGet]
        public async Task<IActionResult> GetMoviesAsync()
        {
            var movies = await movieCommand.GetMoviesAsync();
            return Ok(movies);
        }
    }

// Unit-Test:

public class SampleControllerTest
    {
        private IEnumerable<Movie> MovieList()
        {
            IList<Movie> movies = new List<Movie>()
            {
                new Movie()
                {
                    ID =1,
                    Title = "Test",
                    ReleaseDate = DateTime.Now,
                    RunningTimeInMinutes = 100
                }
            };
            return movies;
        }

        private SampleController GetSampleController()
        {
            var command = new Mock<ICommand>();

            return new SampleController(command.Object);
        }

        [Fact]
        public async Task GetMovies_Test()
        {
            // Arrange
            var controller = GetSampleController();
            var commadMock = new Mock<ICommand>();
            // How to setup moq here?
            commadMock.Setup(s => s.GetMoviesAsync()).Returns(Task.FromResult<IEnumerable<Movie>>(MovieList())).Verifiable();
            // Act
            var response = await controller.GetMoviesAsync() as OkObjectResult;
            // Problem is here, 
            var li=response.Value as IEnumerable<Movie>;
         }
    }

Solution

  • What am I doing wrong?

    Two completely different mocks are being used.

    One is used to create the controller

    private SampleController GetSampleController()
    {
        var command = new Mock<ICommand>();
    
        return new SampleController(command.Object);
    }
    

    and another is being created and setup in the test.

    var controller = GetSampleController();
    var commadMock = new Mock<ICommand>();
    // How to setup moq here?
    commadMock.Setup(s => s.GetMoviesAsync()).Returns(Task.FromResult<IEnumerable<Movie>>(MovieList())).Verifiable();
    

    To solve this, use the same mock to get the desired behavior

    [Fact]
    public async Task GetMovies_Test() {
        // Arrange
        var commadMock = new Mock<ICommand>();
        var controller = new SampleController(commadMock.Object); //<---
        commadMock
            .Setup(_ => _.GetMoviesAsync())
            .ReturnsAsync(MovieList())
            .Verifiable();
    
        // Act
        var response = await controller.GetMoviesAsync() as OkObjectResult;
    
        //Assert
        var list = response.Value as IEnumerable<Movie>;
    
        //...
     }
    

    Note the use of ReturnsAsync to setup the returned Task