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);
}
Related
In my test project i am using xUnit with Moq,
in my controller test class i also need an object of type Mock<UserManager<ApplicationUser>> to get the current user informations.
That's why i am using Moq to Setup the async method FindByIdAsync the setup is configured like this :
public async Task EntrsAdd_ShouldReturnSuccessJsonResult_WhenModelIdIsNull()
{
//Arrange
var id = _fixture.Create<string>();
ApplicationUser applicationUserMock = _fixture.Create<ApplicationUser>();
var viewModelMock = _fixture.Create<AddOrUpdateEntrViewModel>();
viewModelMock.Id = null;
_userManager.Setup(u => u.FindByIdAsync(id))
.Returns(Task.FromResult<ApplicationUser>(applicationUserMock));
//Act
var result = await _sutEntrsController.Add(viewModelMock).ConfigureAwait(false);
int test = 0;
//Assert
}
the method i am testing in the controller is:
public async Task<IActionResult> Add(AddOrUpdateEntrViewModel model)
{
var user = await _userManager.FindByIdAsync(model.UsrId);
var entr = _mapper.Map<Entr>(model);
entr.Usr = $"{user.FirstName} {user.LastName}";
if (model.Id is null)
{
await _entrService.AddAsync(entr);
}
else
{
await _entrService.UpdateAsync(entr);
}
return new JsonResult("success.");
}
The problem is that the setup uses the id variable and the corresponding property in the viewmodel is not set.
Either set the correct id for UsrId on the ViewModelMock or relax the setup by using It.IsAny<string>():
var viewModelMock = _fixture.Create<AddOrUpdateEntrViewModel>();
viewModelMock.Id = null;
viewModelMock.UsrId = id;
or
_userManager.Setup(u => u.FindByIdAsync(It.IsAny<string>()))
.Returns(Task.FromResult<ApplicationUser>(applicationUserMock));
My controller for the delete method :
[HttpDelete("{toDoListId}")]
public async Task<ActionResult> DeleteToDoList(int toDoListId)
{
var toDoListEntity = await _toDoListRepository.GetSpecificTodoAsync(toDoListId);
if (toDoListEntity == null)
{
return NotFound();
}
_toDoListRepository.DeleteToDoList(toDoListEntity);
await _toDoListRepository.SaveChangesAsync();
return NoContent();
}
My repository :
public async Task<ToDoList?> GetSpecificTodoAsync(int taskId)
{
return await _context.ToDoLists.Where(c => c.Id == taskId).FirstOrDefaultAsync();
}
public void DeleteToDoList(ToDoList toDoListDto)
{
_context.ToDoLists.Remove(toDoListDto);
}
My testcase for checking if the item got deleted and if it returns no content after being deleted. But both of my test cases are failing. Any help on how to write test cases for the delete part, I would be really grateful. I am also trying to test other methods but I am unfortunately stuck here. Please kindly help me
public class UnitTest1
{
private readonly Mock<IToDoListRepository> repositoryStub = new ();
private readonly Mock<IMapper> mapper = new Mock<IMapper>();
private readonly Random Rand = new();
private ToDoList GenerateRandomItem()
{
return new()
{
Id = Rand.Next(),
Description= Guid.NewGuid().ToString(),
Title = Guid.NewGuid().ToString(),
StartDate = DateTime.Now,
EndDate = DateTime.Now,
Done = false
};
}
[Fact]
public void Delete_removesEntry()
{
//arrange
var existingItem = GenerateRandomItem();
var controller = new ToDoController(repositoryStub.Object, mapper.Object);
var itemID = existingItem.Id;
//act
controller.DeleteToDoList(itemID);
//assert
Assert.Null(repositoryStub.Object.GetSpecificTodoAsync(itemID));
}
[Fact]
public async Task DeleteItemAsync_WithExistingItem_ReturnNoContent()
{
//Arrange
var existingItem = GenerateRandomItem();
repositoryStub.Setup(repo => repo.GetSpecificTodoAsync(existingItem.Id)).ReturnsAsync((existingItem));
var itemID = existingItem.Id;
var controller = new ToDoController(repositoryStub.Object, mapper.Object);
//Act
var result = await controller.DeleteToDoList(itemID);
//assert
result.Should().BeOfType<NoContentResult>();
}
Both test cases are failing because the mock has not been setup to behave as expected for each test case.
There is also a potential race condition in the shown tests since they are sharing the same mock instance. This will cause issues when setting up the mock as one test case could potentially override the setup of another case.
Update the tests so that they are isolated from each other.
In the first test, the expected behavior can be verified by checking the mock to see if the expected member was invoked.
[Fact]
public async Task DeleteToDoList_Should_RemoveEntry() {
//arrange
ToDoList existingItem = GenerateRandomItem();
var itemID = existingItem.Id;
Mock<IToDoListRepository> repositoryStub = new ();
//Setup expected behavior of mock
repositoryStub
.Setup(_ => _.GetSpecificTodoAsync(itemID))
.ReturnsAsync(existingItem);
var controller = new ToDoController(repositoryStub.Object, mapper.Object);
//act
await controller.DeleteToDoList(itemID);
//assert
repositoryStub.Verify(_ => _.DeleteToDoList(existingItem));
}
In the other test, the mock needs be setup to make sure the subject executes to completion.
[Fact]
public async Task DeleteToDoList_WithExistingItem_Should_ReturnNoContent() {
//Arrange
ToDoList existingItem = GenerateRandomItem();
var itemID = existingItem.Id;
Mock<IToDoListRepository> repositoryStub = new ();
//Setup expected behavior of mock
repositoryStub
.Setup(_ => _.GetSpecificTodoAsync(itemID))
.ReturnsAsync(existingItem);
repositoryStub.Setup(_ => _.SaveChangesAsync()).ReturnsAsynt(true);
var controller = new ToDoController(repositoryStub.Object, mapper.Object);
//Act
ActionResult result = await controller.DeleteToDoList(itemID);
//assert
result.Should().BeOfType<NoContentResult>();
}
I'm trying to assert an IActionResult which returns a JsonResult. I'm unable to access the IActionResult Values.
How can I do that?
UPDATE
This is the code.
[Fact]
public async void AppendEmailTemplateUrl_ReturnOk()
{
// Arrange
var mockLogger = new Mock<ILogger<EmailController>>();
var mockMapper = new Mock<IMapper>();
var mockEmsWorkUnit = new Mock<IEmsWorkUnit>();
var mockAzureBlob = new Mock<IAzureBlob>();
// Setup
var userRequestTemplateString = File.ReadAllText(#".\EmailController\UserRequestTemplate.txt");
mockAzureBlob.Setup(blob => blob.GetHtmlBlob(It.IsAny<string>(), It.IsAny<Uri>()))
.ReturnsAsync(userRequestTemplateString);
var emailController = new EmailController(mockLogger.Object, mockMapper.Object, mockEmsWorkUnit.Object, mockAzureBlob.Object);
var jsonString = File.ReadAllText(#".\EmailController\TemplateUrlOk.json");
var testEmailUrlDto = GeneralHelpers.Deserialize<EmailUrlDto>(jsonString);
// Act
var result = await emailController.AppendEmailTemplateUrl(testEmailUrlDto);
// Assert
}
Cast the JsonResult.Value back to the known type to be formatted and perform your assertions on that
//...omitted for brevity
// Act
IActionResult result = await emailController.AppendEmailTemplateUrl(testEmailUrlDto);
//Assert
var actual = result as JsonResult;
Assert.IsNotNull(actual);
var model = actual.Value as ApiResult;
Assert.IsNotNull(model);
//...assert model
Also refactor the test to use async Task and not async void
[Fact]
public async Task AppendEmailTemplateUrl_ReturnOk() {
//...omitted for brevity
}
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>;
//...
}