Unit testing an Controller with AutoMapper issue - c#

I am trying to test a controller in my asp.netcore application. The test is failing because of auto-mapper.
I tried to mock to the auto-mapper but i do not know how to use it correctly.
Would anyone be able to suggest a way of overcoming this?
Thanks.
BooksController.cs
[HttpGet("{id:int}")]
public IActionResult GetBook(int id)
{
var bookfromRepo = _repository.GetBook(id);
var book = Mapper.Map<BookDto>(bookfromRepo);
return Ok(book);
}
startup.cs
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Data.Database.Entities.Book, BookDto>();
});
ControllerTest.cs
[Fact(DisplayName = "GetBook")]
public void GetBook()
{
//act
var fakerepository = new Mock<IBPDRepository>();
var sut = new BooksController(fakerepository.Object);
//act
var book = new BookDto();
var viewModelBook = new BookDto {
Id = 1,
Name = "C#",
Review = "good",
Pages = "500",
Rating = "8",
Price ="$10.00"
};
//var mockMapper = new Mock //stuck here;
sut.GetBook(1);
//assert
IActionResult actionResult = sut.GetBook(2);
Assert.Equal("C#",viewModelBook.Name);
}

Change your Mapper to an IMapper, and then you can write something like that for the UnitTest :
(I'm doing that free-hand, so there might be slight adjustments to make)
[Fact(DisplayName = "GetBook")]
public void GetBook()
{
// Arrange
var mockBook1 = new Mock<BookDto>(Behavior = MockBehavior.Strict);
var mockBook2 = new Mock<BookDto>(Behavior = MockBehavior.Strict);
var mockRepository = new Mock<IBPDRepository>(Behavior = MockBehavior.Strict);
mockRepository.Setup(r => r.GetBook(It.Is<int>(1)).Returns(mockBook1.Object)
var mockMapper = new Mock<IAutoMapper>(Behavior = MockBehavior.Strict);
mockMapper.Setup(m => m.Map<BookDto>(mockBook1.Object)).Returns(mockBook2.Object);
// You might have to change the constructor.
var sut = new BooksController(mockRepository.Object, mockMapper.Object);
IActionResult actionResult;
// Act
actionResult = sut.GetBook(1);
var actualBook = actionResult.Model as BookDto;
// Assert
Assert.Equal(mockBook2.Object, actualBook);
}
The reason why I'd use mockBook rather than straight BookDto is that this way, combined with the Strict behavior, you know the method didn't change anything on it since you did no setup on it.

Related

Xunit -Moq always returning a null value

I am having an issue with my moq when I try to return data, of serviceResponse but it's not coming
I tried to write unit test in Xunit for service layer
My controller
[HttpGet]
public async Task<IActionResult> GetHospitals(
[FromQuery] HospitalRequestFilter hospitalRequestFilter,
[FromServices] IOptions<ApiBehaviorOptions> options)
{
var serviceResponse = await this._hospitalService.GetHospitalsAsync(hospitalRequestFilter, true);
return OkResponse<HospitalQueryModel>(serviceResponse, true);
}
My controller's unit test
public async Task GetHospitals_WithOutFilter_ReturnsAllData()
{
//Arrange
MockServiceFactory mockServiceFactory = new MockServiceFactory();
var hospitalServiceMock = mockServiceFactory.GetHospitals();
var loggerMoq = new Mock<ILogger<HospitalsController>>();
ILogger<HospitalsController> logger = loggerMoq.Object;
ApiBehaviorOptions apiBeaviorOptions = new ApiBehaviorOptions() { };
var mock = new Mock<IOptions<ApiBehaviorOptions>>();
mock.Setup(ap => ap.Value).Returns(apiBeaviorOptions);
var hospitalValidation = mockServiceFactory.GetHospitalValidation();
HospitalsController HospitalController = new HospitalsController(logger,hospitalServiceMock,hospitalValidation);
//Act
var filter = new HospitalRequestFilter() { Code="Abc",Name="Abc hospital"};
var hospital = await HospitalController.GetHospitals(filter,mock.Object);
//Assert
Assert.NotNull(hospital);
}

Could not find a parameterless constructor

i'm new to unit testing and Moq. I wrote 4 tests who all throw the same exception and i think i need to add these parameters CombatHelperContext, IMapper when mocking the CharacterRepository but how do i do that?
My goal is to test crud functionality, views and more.
public class CharacterTests
{
[Fact]
public async Task GetAll_ReturnsAViewResult_WithAListOfCharacters()
{
// Arrange
var mockRepo = new Mock<CharacterRepository>();
mockRepo.Setup(repo => repo.GetAll())
.Returns(GetTestCharacters());
var controller = new CharacterController(mockRepo.Object);
// Act
var result = await controller.Get();
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<List<CharacterDto>>(
viewResult.ViewData.Model);
Assert.Equal(4, model.Count());
}
[Fact]
public async Task Delete_Character()
{
// Arrange
var mockRepo = new Mock<CharacterRepository>();
mockRepo.Setup(repo => repo.Delete(1));
var controller = new CharacterController(mockRepo.Object);
var characters = GetTestCharacters();
// Act
var result = await controller.Get();
// Assert
Assert.Null(characters.Where(c => c.Id == 1));
}
[Fact]
public async Task Post_NewCharacter_ReturnsInViewResult()
{
// Arrange
CharacterDto newCharacterDto = new CharacterDto();
newCharacterDto.Id = 5;
var mockRepo = new Mock<CharacterRepository>();
mockRepo.Setup(repo => repo.Add(newCharacterDto));
var controller = new CharacterController(mockRepo.Object);
var characters = GetTestCharacters();
// Act
var result = await controller.Get();
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<List<CharacterDto>>(
viewResult.ViewData.Model);
Assert.Equal(5, model.Count());
}
[Fact]
public async Task Update_Character()
{
// Arrange
var mockRepo = new Mock<CharacterRepository>();
var characters = GetTestCharacters();
CharacterDto characterToUpdate = characters.FirstOrDefault(c => c.Name == "Zero Two");
var controller = new CharacterController(mockRepo.Object);
// Act
var result = await controller.Get();
characterToUpdate.Name = "Zero Three";
mockRepo.Setup(repo => repo.Update(characterToUpdate));
// Assert
Assert.NotNull(characters.FirstOrDefault(c => c.Name == "Zero Three"));
}
private IQueryable<CharacterDto> GetTestCharacters()
{
var characters = new List<CharacterDto>();
characters.Add(new CharacterDto()
{
Id = 1,
Name = "Zero Two"
});
characters.Add(
new CharacterDto
{
Id = 2,
Name = "Ander"
});
characters.Add(
new CharacterDto
{
Id = 3,
Name = "Jingles"
});
characters.Add(new CharacterDto
{
Id = 4,
Name = "Arthas Menethil"
});
var queryableCharacters = characters.AsQueryable();
return queryableCharacters;
}
}
This the Repository i'm mocking
public class CharacterRepository : MappingRepository<Character, CharacterDto>
{
public CharacterRepository(CombatHelperContext combatHelperContext, IMapper mapper) : base(combatHelperContext, mapper)
{
}
}
Depend on abstraction rather than implementation - create repository interface:
public interface ICharacterRepository
{
IEnumerable<Character> GetAll();
void Delete(int id);
void Add(Character character);
}
Now mocking works like a charm:
var mockRepo = new Mock<ICharacterRepository>();
Also consider using something like AutoFixture or NBuilder to generate test objects.
[Fact]
public async Task GetAll_Returns_ViewResult_With_List_Of_Characters()
{
// Arrange
var fixture = new Fixture();
var characters = fixture.CreateMany<Character>();
var mockRepo = new Mock<ICharacterRepository>();
mockRepo.Setup(repo => repo.GetAll()).Returns(characters);
var controller = new CharacterController(mockRepo.Object);
// Act
var result = await controller.Get();
// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<List<CharacterDto>>(viewResult.ViewData.Model);
Assert.Equal(characters.Count(), model.Count());
}
If you cannot change current implementation and depend on interface, then you should provide constructor arguments as params list to new mock:
var combatHelperContext = new CombatHelperContext();
var mapperMock = new Mock<IMapper>();
var mockRepo = new Mock<CharacterRepository>(combatHelperContext, mapperMock.Object);

How do you unit test HTTP Response/Requests in c# controller?

I am trying to unit test a c# controller method. I have looked up many questions and nothing quite gives me instructions on how to unit test the API controller. The code that is correct is below for the method. How do you unit test for the brackets.
I have figured out how to test the method "Reverse Payment", but I am using moq and xunit to test the actual c# method. This is my current unit test:
public class PaymentsControllerTests : BackOfficeIntegrationTestBase
{
private readonly CurrentDateProvider _currentDateProvider;
[BackOfficeRolesAuthorize(BackOfficeUserRole.Admin, BackOfficeUserRole.CSR, BackOfficeUserRole.DealerSupportRep,
BackOfficeUserRole.CSRManager)]
[Fact]
public async Task AdminReversalPermissions()
{
IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
var mediator = fixture.Freeze<Mock<IMediator>>();
var currentDateProvider = fixture.Freeze<CurrentDateProvider>();
var mockRepo = new Mock<IMediator>();
var controller = new PaymentsController(mockRepo.Object);
// Setup Dependencies
//DataContext dataContext = SetUpDatabase(fixture);
ReversePaymentSetup(fixture, mediator);
var result = await controller.ReversePayment(LeaseInfo.ApplicationId, 100);
var viewResult = result as NoContentResult;
Assert.NotNull(viewResult);
}
private void ReversePaymentSetup(IFixture fixture, Mock<IMediator> mediator)
{
PaymentData data = new PaymentData();
//Mock the mediator
var paymentPlan = new Data.Model.PaymentPlan()
{
LeaseId = 1,
LeaseTerm = LeaseTerm.Year,
DefermentDays = 5,
FirstPaymentDate = DateTime.ParseExact("01/01/2019", "d", CultureInfo.InvariantCulture),
StoreState = "VA"
};
var responseData = new BuildPaymentPlanResponse();
responseData.Data = new BuildPaymentPlanResponse.InitializePaymentPlanResponseData()
{
PaymentPlan = paymentPlan
};
PaymentStatusChangeManualRequest request = fixture.Build<PaymentStatusChangeManualRequest>()
.With(x => x.PaymentPlanId, LeaseInfo.ApplicationId)
.With(x => x.PaymentId, 100)
.With(x => x.Status, PaymentStatus.Reversed)
.Create();
Assert.Equal(PaymentStatus.Reversed, request.Status);
Assert.Equal(100, request.PaymentId);
Assert.NotNull(LeaseInfo.ApplicationId);
}
}
}
[ProducesResponseType(typeof(ErrorResponse), (int)HttpStatusCode.NotFound)]
[HttpPut("{paymentId}/ReversePayment")]
[BackOfficeRolesAuthorize(BackOfficeUserRole.Admin, BackOfficeUserRole.CSR, BackOfficeUserRole.DealerSupportRep,
BackOfficeUserRole.CSRManager)]
public async Task<IActionResult> ReversePayment(int paymentPlanId, int paymentId)
{
await _mediator.Send(new PaymentStatusChangeManualRequest
{
PaymentPlanId = paymentPlanId,
PaymentId = paymentId,
Status = PaymentStatus.Reversed
});
return NoContent();
}

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>;
}
}
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
It seems that you are not using the correct mock on the Controller. The one that you are using does not have any setup on top of the method GetMoviesAsync
For me helped almost the solution offered by Nkosi but with little difference
[Fact]
public async Task GetMovies_Test() {
// Arrange
var commadMock = new Mock<ICommand>();
var controller = new SampleController(commadMock.Object); //<---
commadMock
.Setup(_ => _.GetMoviesAsync())
.ReturnsAsync(MovieList());
// Act
var response = await controller.GetMoviesAsync();
//Assert
var returnValue = Assert.IsType<ViewResult>(response);
var model = returnValue.Model as IEnumerable<Movie>;
//...
}

Automapper in xUnit testing and .NET Core 2.0

I have .NET Core 2.0 Project which contains Repository pattern and xUnit testing.
Now, here is some of it's code.
Controller:
public class SchedulesController : Controller
{
private readonly IScheduleRepository repository;
private readonly IMapper mapper;
public SchedulesController(IScheduleRepository repository, IMapper mapper)
{
this.repository = repository;
this.mapper = mapper;
}
[HttpGet]
public IActionResult Get()
{
var result = mapper.Map<IEnumerable<Schedule>, IEnumerable<ScheduleDto>>(source: repository.items);
return new OkObjectResult(result);
}
}
My Test Class:
public class SchedulesControllerTests
{
[Fact]
public void CanGet()
{
try
{
//Arrange
Mock<IScheduleRepository> mockRepo = new Mock<IScheduleRepository>();
mockRepo.Setup(m => m.items).Returns(new Schedule[]
{
new Schedule() { Id=1, Title = "Schedule1" },
new Schedule() { Id=2, Title = "Schedule2" },
new Schedule() { Id=3, Title = "Schedule3" }
});
var mockMapper = new Mock<IMapper>();
mockMapper.Setup(x => x.Map<Schedule>(It.IsAny<ScheduleDto>()))
.Returns((ScheduleDto source) => new Schedule() { Title = source.Title });
SchedulesController controller = new SchedulesController(repository: mockRepo.Object, mapper: mockMapper.Object);
//Act
var result = controller.Get();
//Assert
var okResult = result as OkObjectResult;
Assert.NotNull(okResult);
var model = okResult.Value as IEnumerable<ScheduleDto>;
Assert.NotNull(model);
}
catch (Exception ex)
{
//Assert
Assert.False(false, ex.Message);
}
}
}
Issue I Am facing.
My Issue is that when I run this code with database context and execute Get() method, it works fine, it gives me all results.
But when I tries to run test case, it's not returning any data of Dto object.
When I debugged I found that
I am getting my test object in controller using mockRepo.
But it looks like Auto mapper is not initialized correctly, because while mapping it's not returning anything in
var result = mapper.Map<IEnumerable<Schedule>, IEnumerable<ScheduleDto>>(source: repository.items);
What I tried So Far?
I followed all this answers but still it's not working.
Mocking Mapper.Map() in Unit Testing
How to Mock a list transformation using AutoMapper
So, I need help from someone who is good in xUnit and automapper, and need guidance on how to initialize mock Mapper correctly.
Finally it worked for me, I followed this way How to Write xUnit Test for .net core 2.0 Service that uses AutoMapper and Dependency Injection?
Here I am posting my answer and Test Class so if needed other SO's can use.
public class SchedulesControllerTests
{
[Fact]
public void CanGet()
{
try
{
//Arrange
//Repository
Mock<IScheduleRepository> mockRepo = new Mock<IScheduleRepository>();
var schedules = new List<Schedule>(){
new Schedule() { Id=1, Title = "Schedule1" },
new Schedule() { Id=2, Title = "Schedule2" },
new Schedule() { Id=3, Title = "Schedule3" }
};
mockRepo.Setup(m => m.items).Returns(value: schedules);
//auto mapper configuration
var mockMapper = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfile());
});
var mapper = mockMapper.CreateMapper();
SchedulesController controller = new SchedulesController(repository: mockRepo.Object, mapper: mapper);
//Act
var result = controller.Get();
//Assert
var okResult = result as OkObjectResult;
if (okResult != null)
Assert.NotNull(okResult);
var model = okResult.Value as IEnumerable<ScheduleDto>;
if (model.Count() > 0)
{
Assert.NotNull(model);
var expected = model?.FirstOrDefault().Title;
var actual = schedules?.FirstOrDefault().Title;
Assert.Equal(expected: expected, actual: actual);
}
}
catch (Exception ex)
{
//Assert
Assert.False(false, ex.Message);
}
}
}
I needed to inject IMapper, use ProjectTo to get a mapped IQueryable, then implement some more logic on the queryable after the map. So here's what I did to mock it:
var models = new object[]
{
⋮
}.AsQueryable();
var mapper = new Mock<IMapper>();
mapper.Setup(x => x.ProjectTo(
It.IsAny<IQueryable>(),
It.IsAny<object>(),
It.IsAny<Expression<Func<object, object>>[]>()))
.Returns(models);

Categories