0

I'm currently setting up some unit tests to return ID of the cafes using some mocking, but for some reason the result variable always returns null.

Setup in service class which implements the Get method

public async Task<CafeResponse> Get(int cafeId)
        {
            var cafe= await _cafeRepository.GetByIdAsync(cafeId);

            
            return _mapper.Map<CafeResponse>(cafe);
        }

Unit test setup: Currently the result variable shows null? Not sure if this is due to me setting up the mock incorrectly

        [Fact]
        public async Task Get_ShouldReturnCafeArray_WhenCafesInDatabase()
        {
            //Arrange
            var cafeId = 98;
            var cafeName = "bellas";
            var cafeIdGuid = Guid.NewGuid();
            var cafeDesc = "this is my test";
            var cafeTypeId = 1;


            var cafeDto = new Cafe
            {
                CafeId = cafeId,
                Name = cafeName,
                CafeGuid = cafeIdGuid, 
                Description = cafeDesc,
                CafeTypeId = cafeTypeId,
            
            };

            var expected = new CafeResponse();

            var mockCafe = new Mock<IRepositoryAsync<Cafe>>();
            mockCafe.Setup(x => x.GetByIdAsync(cafeId)).ReturnsAsync(cafeDto);

           
            var mockMapper = new Mock<IMapper>();
            mockMapper.Setup(x => x.Map<Cafe, CafeResponse>(It.IsAny<Cafe>())).Returns(expected);

            //Act
            var cafeService = new CafeService(mockCafe.Object, mockMapper.Object);
            var result = await cafeService.Get(cafeId); //always returns null

           
            //Assert
            mockCafe.Verify(x => x.GetByIdAsync(cafeId), Times.Once);
            Assert.Equal(cafeId, result.CafeId);


        }
James McCoy
  • 79
  • 2
  • 9
  • 1
    Are you expecting a filled out cafe response from your mapper? Currently, your mockMapper is returning a blank CafeResponse. – Ben Sampica Jul 26 '20 at 23:06
  • yep i am expecting a cafe response from the mapper, wanted to add more asserts for further testing – James McCoy Jul 26 '20 at 23:08
  • @BenSampica I thought I implemented it correctly? Why is it returning a blank response? – James McCoy Jul 26 '20 at 23:09
  • 1
    because of this line `mockMapper.Setup(x => x.Map(It.IsAny())).Returns(expected);`.`expected` variable is an empty object – ilkerkaran Jul 26 '20 at 23:10
  • I've got a mapper setup in my service class as well maybe I should be trying to use that instead of creating one in this class? – James McCoy Jul 26 '20 at 23:13
  • @ilkerkaran what If I removed that setup line and just passed a new mock mapper into my parameter for the restaurant service like so: var restaurantService = new RestaurantService(mockRestaurant.Object, new Mock().Object); – James McCoy Jul 26 '20 at 23:30
  • @JamesMcCoy use an actual mapper and then assert the members of the result. – Nkosi Jul 26 '20 at 23:36

1 Answers1

2

The reason that you're getting a null result with the code that you have is because for IMapper you're mocking:

TDestination Map<TSource, TDestination>(TSource source);

but your actual code is using:

TDestination Map<TDestination>(object source);

So if you just want the test to return your "expected" instance of CafeResponse, then you need to update your Mock<IMapper> setup to be:

mockMapper.Setup(x => x.Map<CafeResponse>(It.IsAny<Cafe>())).Returns(expected);

The more appropriate solution as pointed out in the comments would be to simply create a Mapper instance for your test:

var mapper = new MapperConfiguration(cfg =>
{
    cfg.AddProfile<MyProfile>();
}).CreateMapper();

Otherwise, you're just testing that you're mock is returning what you tell it to and not really verifying any functionality in your code.

devNull
  • 3,849
  • 1
  • 16
  • 16
  • I See! So currently it's not showing as null anymore! But for some reason the CafeResponse is not returning any data back so it's just an empty CafeResponse as the result – James McCoy Jul 26 '20 at 23:59
  • 1
    @JamesMcCoy That's going to happen since you're mocking `IMapper` and telling it what to return. Your classes aren't actually being mapped. The solution to that, as mentioned, would be to use a real `Mapper` instance – devNull Jul 27 '20 at 00:08
  • where you mention using the MapperConfiguration what is the ?? – James McCoy Jul 27 '20 at 00:39
  • 1
    That's just referring to a configuration [Profile](https://docs.automapper.org/en/stable/Configuration.html#profile-instances). You could also just supply whatever mapping configuration you need. Having a `Profile` allows you to reuse the configuration – devNull Jul 27 '20 at 00:55
  • 1
    I've just created a mapper now: var mapper = new MapperConfiguration(cfg => { cfg.AddProfile(new AutoMapperProfile()); }).CreateMapper(); – James McCoy Jul 27 '20 at 01:03
  • How would I create a case which does a check if it fails? – James McCoy Jul 27 '20 at 01:48
  • @JamesMcCoy If you want to simulate the mapper throwing an exception, the best way would probably be to setup a mock mapper (as you were doing before) and have that throw an exception (see [this answer](https://stackoverflow.com/a/10323930/5803406)) – devNull Jul 27 '20 at 02:08
  • I see was just a bit confused on what I really want to test using mocks - I originally wanted to test what I have created as data vs whats actually in the database through mocking so not sure if that's possible? Is there a way to check for authentication + Returning empty cafes etc? with what I currenlty have setup – James McCoy Jul 27 '20 at 02:15
  • Because I assumed when if I had an ID which didn't exist my tests should fail but it seems to be passing – James McCoy Jul 27 '20 at 02:15