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);
Related
I'm creating a random object that I'm expecting back from the test, and using the ReturnsAsync method when setting up the mock repo. The controller inside the Unit Test is returning null, however.
The main difference between my code and a lot of the others is that I'm using AutoMapper to return the DTO object in my controller as an OK object. I'm not sure if that's causing my issue.
Controller Instantiation
private readonly ISuperHeroRepo _repo;
public IMapper _mapper { get; }
public SuperHeroController(ISuperHeroRepo repo, IMapper mapper)
{
_repo = repo;
_mapper = mapper;
}
Repo Method
public async Task<SuperHero> GetSuperHero(int id)
{
return await _db.SuperHeros.FindAsync(id);
}
Mapper Profile
public class SuperHeroProfiles : Profile
{
public SuperHeroProfiles()
{
//Source -> Target
CreateMap<SuperHero, SuperHeroReadDTO>()
.ForMember(target => target.LegalName, option => option.MapFrom(source => $"{source.LegalFirstName} {source.LegalLastName}"))
.ForMember(target => target.Jurisdiction, option => option.MapFrom(source => $"{source.JurisdictionCity}, {source.JurisdictionState}"));
CreateMap<SuperHero, SuperHeroDTO>();
}
}
Controller Method
[HttpGet("{id}")]
public async Task<ActionResult<SuperHeroReadDTO>> Get(int id)
{
var hero = await _repo.GetSuperHero(id);
if (hero == null)
{
return NotFound("Hero Not Found");
}
else
{
// This is where it might be breaking
return Ok(_mapper.Map<SuperHeroReadDTO>(hero));
}
}
Unit Test
// Instantiated
readonly Mock<ISuperHeroRepo> repoMock = new();
readonly Mock<IMapper> mapperMock = new();
private readonly Random random = new();
........
[Fact]
public async Task Get_WithExistingHero_ReturnsExpectedSuperHero()
{
// Arrange
SuperHero expected = CreateRandomSuperHero();
repoMock.Setup(repo => repo.GetSuperHero(It.IsAny<int>()))
.ReturnsAsync(expected);
var controller = new SuperHeroController(repoMock.Object, mapperMock.Object);
// Act - This returns null. Debugging in the controller, I get the object back from repo
var result = await controller.Get(random.Next());
// Assert
Assert.IsType<SuperHeroReadDTO>(result.Value);
var dto = result.Value;
Assert.Equal(expected.SuperHeroName, dto.SuperHeroName);
Assert.Equal($"{expected.LegalFirstName} {expected.LegalLastName}", dto.LegalName);
Assert.Equal($"{expected.JurisdictionCity}, {expected.JurisdictionState}", dto.Jurisdiction);
}
Edited: Added the controller instantiation, and the Mapper Profile. Not sure if it'll add more info.
#shree.pat18 was indeed correct. I did end up needing to set up the Mapper object in the Unit Test and passing it back into the controller. I'll need to refactor, but here below is what resolved it:
[Fact]
public async Task Get_WithExistingHero_ReturnsExpectedSuperHero()
{
// Arrange
SuperHero expected = CreateRandomSuperHero();
repoMock.Setup(repo => repo.GetSuperHero(It.IsAny<int>()))
.ReturnsAsync(expected);
// Setup of the mock Mapper
var mockMapper = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new SuperHeroProfiles());
});
var mapper = mockMapper.CreateMapper();
var controller = new SuperHeroController(repoMock.Object, mapper);
// Act
var result = await controller.Get(random.Next());
// Assert
Assert.IsType<SuperHeroReadDTO>(result.Value);
var dto = result.Value;
Assert.Equal(expected.SuperHeroName, dto.SuperHeroName);
Assert.Equal($"{expected.LegalFirstName} {expected.LegalLastName}", dto.LegalName);
Assert.Equal($"{expected.JurisdictionCity}, {expected.JurisdictionState}", dto.Jurisdiction);
}
I've read similar questions but could not manage to solve my own. I'm using xUnit and I'm running into an issue when one of my methods calls, it's returning null but in fact that I have mocked it.
Interface
public interface IApplicantService
{
Task<Applicant> AddAsync(Applicant applicant);
// other methods
}
Test Case
public class ApplicationControllerTests
{
private readonly Mock<IApplicantService> _mockApplicantService;
private readonly ApplicantController _applicantController;
private readonly IMapper _mockMapper;
public ApplicationControllerTests()
{
_mockApplicantService = new Mock<IApplicantService>();
var mapperConfig = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new ResourceToModelProfile());
cfg.AddProfile(new ModelToResourceProfile());
});
_mockMapper = mapperConfig.CreateMapper();
_applicantController = new ApplicantController(_mockApplicantService.Object, _mockMapper);
}
[Fact]
public async void CreateAsync_WhenApplicantNotExist_ShouldReturn_CreatedAtActionResult_With_Resource()
{
var applicantDto = new ApplicantCreateDto
{
PersonId = 1,
VacancyId = 1
};
_mockApplicantService.Setup(e => e.AddAsync(It.IsAny<Applicant>()))
.Returns(Task.FromResult(new Applicant { Id = 1, PersonId = 1, VacancyId = 1}));
var result = await _applicantController.CreateAsync(applicantDto);
var createdAtActionResult = result as CreatedAtActionResult;
var model = createdAtActionResult.Value as ApplicantResponseDto;
var actual = model.PersonId;
Assert.NotNull(model);
Assert.Equal(1, actual);
Assert.NotNull(createdAtActionResult);
}
}
Controller
[HttpPost]
[Route("CreateAsync")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CreateAsync([FromBody] ApplicantCreateDto applicantCreateDto)
{
try
{
var applicant = _mapper.Map<ApplicantCreateDto, Applicant>(applicantCreateDto);
var result = await _applicantService.AddAsync(applicant);
// here, result is null, but it was mocked to return an Applicant object
var resource = _mapper.Map<Applicant, ApplicantResponseDto>(result);
return CreatedAtAction(nameof(GetAsync), new { id = result.Id }, resource);
}
catch (ResourceExistException ex)
{
return Conflict(ex.Message);
}
catch(Exception ex)
{
// log exception
return StatusCode(500);
}
}
The mocked method is returning null and I'm getting System.NullReferenceException
This is how your fixed unit test could look like:
[Fact]
public async Task CreateAsync_WhenApplicantNotExist_ShouldReturn_CreatedAtActionResult_With_Resource()
{
//Arrange
var applicantDto = new ApplicantCreateDto { PersonId = 1, VacancyId = 1 };
var applicant = new Applicant { Id = 1, PersonId = 1, VacancyId = 1 };
_mockApplicantService
.Setup(svc => svc.AddAsync(It.IsAny<Applicant>()))
.ReturnsAsync(applicant);
//Act
var result = await _applicantController.CreateAsync(applicantDto);
//Assert
var createdAtActionResult = Assert.IsAssignableFrom<CreatedAtActionResult>(result);
var model = Assert.IsAssignableFrom<ApplicationResponseDto>(createdAtActionResult.Value);
Assert.Equal(1, model.PersonId);
}
I've replaced async void to async Task that way your await will be evaluated properly
I've changed the Returns(Task.FromResult(...)) to ReturnsAsync(...) because this is the recommended way to specify return value in case of async methods
I've also added some comments to separate the different phases of your unit test from each other (Arrange-Act-Assert)
I've changed your assertion logic to use IsAssingableFrom to verify the type itself rather than doing null checks
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();
}
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>;
//...
}
I'm trying to unit test some Web Api 2 Controllers that use Entity Framework 6 but having issues with the loading of the related entities after the entity has been added. I'm using Moq to create a mocked DbContext and DbSet, and have added
public virtual void MarkAsModified<T>(T item) where T : class
{
Entry(item).State = EntityState.Modified;
}
to get around the _db.Entry(foo).State = EntityState.Modified; issue on a Put action.
The Api Action is a Post in this simplified example where we need to get back 2 related entities (Bar and Qux).
[ResponseType(typeof (Foo))]
public async Task<IHttpActionResult> PostFoo(Foo foo)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//Do other stuff
_db.Foos.Add(foo);
_db.Entry(foo).Reference(x => x.Bar).Load();
_db.Entry(foo).Reference(x => x.Qux).Load();
await _db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new {id = foo.Id},foo);
}
And then a simplified test would be
[TestMethod]
public async Task PostFoo()
{
var model = new Foo
{
Name="New Foo",
QuxId = 99,
Qux = null,
BarId = 66,
Bar = null
};
var result = await _controller.PostFoo(model) as CreatedAtRouteNegotiatedContentResult<Foo>;
Assert.IsNotNull(result);
Assert.IsNotNull(result.Qux);
Assert.IsNotNull(result.Bar);
}
Is there a more mock-friendly way of doing _db.Entry(foo).Reference(x => x.Bar).Load();
The general idea about the solution can be seen here
Mocking Entity Framework when Unit Testing ASP.NET Web API 2: dependency injection
Currently, your controller is coupled too tightly to EF so my advice would be to abstract the DbContext and DbSet dependency out of the controller so that it can become mock-friendly.
To get around _db.Entry(foo).Reference(x => x.Bar).Load() here is a simplified abstraction of the dependent actions based on what you are using in your post
public interface IUnitOfWork {
void Add<T>(T item) where T : class;
void MarkAsModified<T>(T item) where T : class;
void LoadRelatedEntity<T, TRelated>(T item, Expression<Func<T, TRelated>> exp)
where T : class
where TRelated : class;
Task SaveChangesAsync();
}
and allow a concrete implementation to be able to do this.
public void LoadRelatedEntity<T, TRelated>(T item, Expression<Func<T, TRelated>> exp)
where T : class
where TRelated : class
{
_db.Entry(item).Reference(exp).Load();
}
This dependency can now be injected into the controller and can also be mocked.
Here is a simplified version of a potential controller
public class FooController : ApiController {
IUnitOfWork unitOfWork;
public FooController (IUnitOfWork uow) {
this.unitOfWork = uow;
}
[ResponseType(typeof(Foo))]
public async Task<IHttpActionResult> PostFoo(Foo foo) {
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
//Do other stuff
unitOfWork.Add(foo);
await unitOfWork.SaveChangesAsync();
//Load related entities
unitOfWork.LoadRelatedEntity(foo, x => x.Bar);
unitOfWork.LoadRelatedEntity(foo, x => x.Qux);
return CreatedAtRoute("DefaultApi", new { id = foo.Id }, foo);
}
}
From there it's just a matter of creating your test.
[TestMethod]
public async Task TestPostFoo() {
//Arrange
bool saved = false;
var model = new Foo {
Name = "New Foo",
QuxId = 99,
Qux = null,
BarId = 66,
Bar = null
};
var mockUnitOfWork = new Moq.Mock<IUnitOfWork>();
mockUnitOfWork.Setup(x => x.SaveChangesAsync())
.Returns(() => Task.FromResult(0))
.Callback(() => {
model.Id = 1;
saved = true;
});
mockUnitOfWork
.Setup(x => x.LoadRelatedEntity<Foo, Qux>(It.IsAny<Foo>(), It.IsAny<Expression<Func<Foo, Qux>>>()))
.Callback(() => model.Qux = new Qux());
mockUnitOfWork
.Setup(x => x.LoadRelatedEntity<Foo, Bar>(It.IsAny<Foo>(), It.IsAny<Expression<Func<Foo, Bar>>>()))
.Callback(() => model.Bar = new Bar());
var controller = new TestsFooApiController(mockUnitOfWork.Object);
controller.Request = new HttpRequestMessage { };
controller.Configuration = new HttpConfiguration();
//Act
var result = await controller.PostFoo(model) as CreatedAtRouteNegotiatedContentResult<Foo>;
//Assert
result.Should().NotBeNull();
result.Content.Should().NotBeNull();
result.Content.Id.Should().BeGreaterThan(0);
result.Content.Qux.Should().NotBeNull();
result.Content.Bar.Should().NotBeNull();
saved.Should().BeTrue();
}
Hope this helps