I have something like this to test:
public void example(ModelView modelView)
{
//...
var statustId= 1;
var requests = _unitOfWork.RequestRepository.Get(m => m.RequestStatusId == statusId);
var requests = _unitOfWork.RequestRepository.Get(m => m.RequestTypeId == modelView.RequestTypeId);
var oldRequests = _unitOfWork.RequestRepository.Get(m => m.Created == DateTime.Now.AddDays(-7));
//...
}
How do i mock all the "GET" with different data?
This is what i got so far: not sure what the expression should look like since it is using a variables from the function.
[Test]
public void Test()
{
//Arrange
_requestGenericRepo.Setup(m => m.Get(
It.Is<Expression<Func<Request, bool>>>(e => e.Equals(First GET - using local variable);
_requestGenericRepo.Setup(m => m.Get(
It.Is<Expression<Func<Request, bool>>>(e => e.Equals(Second GET - using variable from modelView));
_requestGenericRepo.Setup(m => m.Get(
It.Is<Expression<Func<Request, bool>>>(e => e.Equals(Third GET));
//Act
var response = _controller.Example( new ModelView
{
RequestTypeId= 1
});
//Assert
...
}
-------------------EDIT: -------------------------------------------
It would be nice to know how to do in the above way but I can change all Get( To Get().Where like this:
public void example(ModelView modelView)
{
//...
var statustId= 1;
var requests = _unitOfWork.RequestRepository.Get().Where(m => m.RequestStatusId == statusId);
var requests = _unitOfWork.RequestRepository.Get().Where(m => m.RequestTypeId == modelView.RequestTypeId);
var oldRequests = _unitOfWork.RequestRepository.Get().Where(m => m.Created == DateTime.Now.AddDays(-7));
//...
}
[Test]
public void Test()
{
//Arrange
_requestGenericRepo.Setup(m => m.Get(
It.IsAny<Expression<Func<Request, bool>>>());
//Act
var response = _controller.Example( new ModelView
{
RequestTypeId= 1
});
//Assert
...
}
What is the return value of the RequestRepository.Get method? You can try to use SetupSequence and choose path you want to test. Something like:
_requestGenericRepo.SetupSequence(m => m.Get(It.IsAny<Expression<Func<Request, bool>>>())
.Returns(/*First call*/)
.Returns(/*Second call*/)
.Returns(/*Third call*/);
Related
I have this class called Handler, which is a MassTransit IConsumer:
public class Handler : IConsumer<ICommand>
{
private readonly IOrderRepository _orderRepository;
public Handler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
}
public async Task Consume(ConsumeContext<ICommand> context)
{
var command = context.Message;
var orderId = new OrderId(command.OrderId);
var order = await _orderRepository.FindOrderAsync(orderId, context.CancellationToken);
if (order is null)
{
await context.RespondAsync(CommandResponse.NotFound);
return;
}
order.Cancel();
await _orderRepository.SaveOrderAsync(order, context.CancellationToken);
await context.RespondAsync(CommandResponse.Submitted);
}
}
I have two unit tests for it. Here's the one that seems to work fine:
[TestMethod]
public async Task Consume_WithExistingOrderId_CancelsOrderAndSavesChangesAndReturnsSubmitted()
{
// Arrange
var mockConsumer = new Mock<IConsumer<ICommand>>();
var mockRepository = new Mock<IOrderRepository>();
var sut = new Handler(mockRepository.Object);
var mockCommand = new Mock<ICommand>();
var mockContext = new Mock<ConsumeContext<ICommand>>();
mockContext.Setup(x => x.Message).Returns(mockCommand.Object);
mockContext.Setup(x => x.RespondAsync(It.IsAny<CommandResponse>())).Returns(Task.CompletedTask);
var existingOrderId = new OrderId(Guid.NewGuid());
mockCommand.Setup(x => x.OrderId).Returns(existingOrderId.Value);
var order = GetTestOrder(existingOrderId);
mockRepository.Setup(x => x.FindOrderAsync(existingOrderId, It.IsAny<CancellationToken>())).ReturnsAsync(order);
// Act
await sut.Consume(mockContext.Object);
// Assert
mockRepository.Verify(x => x.SaveOrderAsync(order, It.IsAny<CancellationToken>()), Times.Once());
mockContext.Verify(x => x.RespondAsync(CommandResponse.Submitted), Times.Once());
order.IsCancelled.Should().BeTrue();
}
And here's the one that isn't doing what I expected:
[TestMethod()]
public async Task Consume_WithNonExistantOrderId_ReturnsNotFoundResponseAndDoesNotSave()
{
// Arrange
var mockRepository = new Mock<IOrderRepository>();
var sut = new Handler(mockRepository.Object);
var mockCommand = new Mock<ICommand>();
var mockContext = new Mock<ConsumeContext<ICommand>>();
mockContext.Setup(x => x.Message).Returns(mockCommand.Object);
mockContext.Setup(x => x.RespondAsync(It.IsAny<CommandResponse>())).Returns(Task.CompletedTask);
var nonExistantOrderId = new OrderId(Guid.NewGuid());
mockCommand.Setup(x => x.OrderId).Returns(nonExistantOrderId.Value);
mockRepository.Setup(x => x.FindOrderAsync(nonExistantOrderId, It.IsAny<CancellationToken>())).ReturnsAsync((Order?)null);
// Act
await sut.Consume(mockContext.Object);
// Assert
mockRepository.Verify(x => x.SaveOrderAsync(It.IsAny<Order>(), It.IsAny<CancellationToken>()), Times.Never());
mockContext.Verify(x => x.RespondAsync(CommandResponse.NotFound), Times.Once());
}
Both unit tests require that the Handler calls the RespondAsync method of the MassTransit context exactly once. However, the second unit test doesn't pass, saying that the method was never called. I don't see why it was never called. When I debug into the method it appears to show the method is called.
I can't tell if my test is wrong or if my system under test is wrong. Can anybody see the problem please?
(Also, if anybody can see how to make my code more testable and my unit tests shorter and simpler that would also be appreciated.)
The problem is with the nonExistantOrderId and using that for the match in expectation.
mockRepository
.Setup(x => x.FindOrderAsync(nonExistantOrderId, It.IsAny<CancellationToken>()))
.ReturnsAsync((Order?)null);
the mock expects to get that specific instance when the subject is being exercised but the subject initialized its own instance which causes the mock to not invoke the async call and exit the subject before that target line can be invoked.
This is why
mockRepository.Verify(x => x.SaveOrderAsync(It.IsAny<Order>(), It.IsAny<CancellationToken>()), Times.Never());
supposedly passed verification, and
mockContext.Verify(x => x.RespondAsync(CommandResponse.NotFound), Times.Once());
failed since the subject code exited before reaching both members that are the targets of your verification.
Loosen the match using It.IsAny<OrderId>()
mockRepository
.Setup(x => x.FindOrderAsync(It.IsAny<OrderId>(), It.IsAny<CancellationToken>()))
.ReturnsAsync((Order?)null);
so that the mocked async call can be invoked and allow the code to flow to completion.
I have accepted Nkosi's answer because it solved the problem stated in the question. Thank you, Nkosi.
However, the resources that were provided by the MassTransit boss-man, #Chris Patterson, were helpful in making a better unit test altogether. That's why I'm posting this alternative answer. This answer rewrites the original unit test to use the MassTransit test harness, and I hope it helps somebody one day.
Chris's links have somehow disappeared from sight. However, I think he posted this:
https://www.youtube.com/watch?v=Cx-Mc0DCpfE&t=545s
And this:
https://masstransit-project.com/usage/testing.html
The rewritten method:
public interface ICommand
{
Guid OrderId { get; }
}
public record Command : ICommand
{
public Command(Guid orderId)
{
OrderId = orderId;
}
public Guid OrderId { get; }
}
public class Handler : IConsumer<ICommand>
{
private readonly IOrderRepository _orderRepository;
public Handler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
}
public async Task Consume(ConsumeContext<ICommand> context)
{
var command = context.Message;
OrderId orderId = new OrderId(command.OrderId);
var order = await _orderRepository.FindOrderAsync(orderId, context.CancellationToken);
if (order is null)
{
await context.RespondAsync(CommandResponse.NotFound);
return;
}
order.Cancel();
await _orderRepository.SaveOrderAsync(order, context.CancellationToken);
await context.RespondAsync(CommandResponse.Submitted);
}
}
The rewritten unit test class:
[TestClass()]
public class Handler_Tests
{
private static OrderId ExistingOrderId = new OrderId("d94108e4-1121-401a-a6ef-c7736054041d");
private static OrderId NonExistentOrderId = new OrderId("daaa72a0-8f8c-4a9b-b4ad-ebefbb6b5aa2");
private static CustomerId ExistingCustomerId = new CustomerId("5fbf40d8-c064-4821-8948-a520863e6242");
[TestMethod()]
public async Task Consume_WithExistingOrderId_CancelsOrderAndSavesChangesAndReturnsSubmitted2()
{
// Arrange
var harness = new InMemoryTestHarness();
var mockRepository = GetMockOrderRepository();
var sut = harness.Consumer(() =>
{
return new Handler(mockRepository.Object);
});
await harness.Start();
try
{
var requestClient = await harness.ConnectRequestClient<ICommand>();
var command = new Command(ExistingOrderId.Value);
// Act
var response = await requestClient.GetResponse<CommandResponse>(command, It.IsAny<CancellationToken>());
// Assert
mockRepository.Verify(x => x.SaveOrderAsync(It.IsAny<Order>(), It.IsAny<CancellationToken>()), Times.Once());
response.Message.Result.Should().Be(CommandResponse.Results.Submitted);
}
finally
{
await harness.Stop();
}
}
[TestMethod()]
public async Task Consume_WithNonExistentOrderId_ReturnsNotFoundResponseAndDoesNotSave()
{
// Arrange
var harness = new InMemoryTestHarness();
var mockRepository = GetMockOrderRepository();
var sut = harness.Consumer(() =>
{
return new Handler(mockRepository.Object);
});
await harness.Start();
try
{
var requestClient = await harness.ConnectRequestClient<ICommand>();
var command = new Command(NonExistentOrderId.Value);
var response = await requestClient.GetResponse<CommandResponse>(command, It.IsAny<CancellationToken>());
mockRepository.Verify(x => x.SaveOrderAsync(It.IsAny<Order>(), It.IsAny<CancellationToken>()), Times.Never());
response.Message.Result.Should().Be(CommandResponse.Results.NotFound);
}
finally
{
await harness.Stop();
}
}
private static Order GetTestOrder(OrderId orderId)
{
var orderItem = GetTestOrderItem();
return Order.Place(orderId, ExistingCustomerId, new[] { orderItem });
}
private static OrderItem GetTestOrderItem()
{
var productId = new ProductId(Guid.NewGuid());
var price = new Price(1, PurchaseCurrency.Usd);
var quantity = new Quantity(1, UnitOfMeasure.Each);
return new OrderItem(productId, quantity, price);
}
private static Mock<IOrderRepository> GetMockOrderRepository()
{
var mockRepository = new Mock<IOrderRepository>();
mockRepository.Setup(x => x.FindOrderAsync(It.IsAny<OrderId>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new InvalidOperationException(
$"This mock is set up to work with {nameof(ExistingOrderId)} and {nameof(NonExistentOrderId)}."));
mockRepository.Setup(x => x.FindOrderAsync(ExistingOrderId, It.IsAny<CancellationToken>()))
.ReturnsAsync(GetTestOrder(ExistingOrderId));
mockRepository.Setup(x => x.FindOrderAsync(NonExistentOrderId, It.IsAny<CancellationToken>()))
.ReturnsAsync((Order?)null);
return mockRepository;
}
}
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 am attempting to mock out some of EF Core's functions.
Originally I was getting the following error
The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IEntityQueryProvider can be used for Entity Framework asynchronous operations.
After looking at this question it almost seems to work but i'm now getting the following:
System.ArgumentNullException : Value cannot be null.
Parameter name: source
at Microsoft.EntityFrameworkCore.Utilities.Check.NotNull[T](T value, String parameterName)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable1 source, Expression1 predicate, CancellationToken cancellationToken)
at Ombi.Core.Rule.Rules.Search.RadarrCacheRule.d__2.MoveNext() in C:\Users\Jamie.Rees\Source\Repos\PlexRequests.Net\src\Ombi.Core\Rule\Rules\Search\RadarrCacheRule.cs:line 25
Here is the test code:
[Test]
public async Task Should_ReturnApproved_WhenMovieIsInRadarr()
{
var list = new List<RadarrCache>(){new RadarrCache
{
TheMovieDbId = 123
}}.AsQueryable();
var radarrMock = new Mock<DbSet<RadarrCache>>();
radarrMock.As<IAsyncEnumerable<RadarrCache>>()
.Setup(m => m.GetEnumerator())
.Returns(new TestAsyncEnumerator<RadarrCache>(list.GetEnumerator()));
radarrMock.As<IQueryable<RadarrCache>>()
.Setup(m => m.Provider)
.Returns(new TestAsyncQueryProvider<RadarrCache>(list.Provider));
radarrMock.As<IQueryable<RadarrCache>>().Setup(m => m.Expression).Returns(list.Expression);
radarrMock.As<IQueryable<RadarrCache>>().Setup(m => m.ElementType).Returns(list.ElementType);
radarrMock.As<IQueryable<RadarrCache>>().Setup(m => m.GetEnumerator()).Returns(() => list.GetEnumerator());
ContextMock.Setup(c => c.Set<RadarrCache>()).Returns(radarrMock.Object);
var request = new SearchMovieViewModel { Id = 123 };
var result =await Rule.Execute(request);
Assert.True(result.Success);
Assert.True(request.Approved);
}
This is the class under test:
public class RadarrCacheRule : BaseSearchRule, IRules<SearchViewModel>
{
public RadarrCacheRule(IOmbiContext ctx)
{
_ctx = ctx;
}
private readonly IOmbiContext _ctx;
public async Task<RuleResult> Execute(SearchViewModel obj)
{
if (obj.Type == RequestType.Movie)
{
// Check if it's in Radarr
var result = await _ctx.RadarrCache.FirstOrDefaultAsync(x => x.TheMovieDbId == obj.Id);
if (result != null)
{
obj.Approved =
true; // It's in radarr so it's approved... Maybe have a new property called "Processing" or something?
}
}
return Success();
}
}
Any idea how I am suppose to do this?
I have the following method:
public async Task<string> GetDescription(int codeId)
{
var Codes = Context.Codes.Where(x => x.Id == codeId).FirstOrDefault();
return Codes.Description;
}
and the following unit test:
[Test]
public async Task GetDescription()
{
var result = await _serivce.GetSpecialtyDescription(1);
Assert.That(result == "description");
}
and I setup my test like this:
public ServicesTests()
{
_dbContext = new Mock<LocalContext>();
var CodeList = new List<Codes>() { new Codes() { Id = 1, Description = "description" } };
var dbSetCodeList = MockDbSet.GetQueryableMockDbSet(CodeList);
_dbContext.Setup(x => x.Codes).Returns(dbSetCodeList.Object);
_context = new DataContext<LocalContext, LocalContext>(_dbContext.Object);
_serivce = new CodesServices(_context);
}
public static Mock<DbSet<T>> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class
{
var queryable = sourceList.AsQueryable();
var dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s));
return dbSet;
}
Which all works fine.
Now, I want to await the function, so do this:
public async Task<string> GetDescription(int codeId)
{
var Codes = await Context.Codes.Where(x => x.Id == codeId).FirstOrDefaultAsync();
return Codes.Description;
}
but this breaks my unit test - even though the code still works.
I have read plenty of articles and posts explaining that this does not work as the async methods cannot be mocked (I think?), but I have not come across anything which shows me how to resolve this.
I would be disappointing if I was forced to choose between awaiting my code or having a unit test, and feel sure there must be a way around this?
I am not happy with the result, but this is the best I can do so far:
public async Task<string> GetDescription(int codeId)
{
var Codes = await GetAll();
return Codes.Description;
}
private async Task<DbSet<Codes>> GetAll()
{
return Context.Codes;
}
If anyone has a better suggestion please let me know.
Please i m having trouble testing this method .
public class EFUrlRepository : IUrlsRepository
{
public EFDbContext context = new EFDbContext();
private Security security = new Security();
public IQueryable<Url> Urls
{
get { return context.Urls; }
}
public bool AddUrl(Url url)
{
if(url.UrlId == 0)
{
context.Urls.Add(url);
context.SaveChanges();
url.UrlCode = security.Encrypt(url.UrlId.ToString());
context.SaveChanges();
return true;
}
return false;
}
}
I am trying to test the addUrl of the class above. I try to implement as explained Here
[TestMethod]
public void CreateUrl_saves_a_url_via_context()
{
var mockSet = new Mock<DbSet<Url>>();
var mockContext = new Mock<EFDbContext>();
mockContext.Setup(m => m.Urls).Returns(mockSet.Object);
var repository = new EFUrlRepository();
Url url = new Url()
{
UrlCode = "TYUyR",
OriginalUrl = "https://fluentvalidation.com",
IpAddress = "127.0.0.1",
PostedDate = DateTime.Now
};
repository.context = mockContext.Object;
repository.AddUrl(url);
mockSet.Verify(m => m.Add(It.IsAny<Url>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
}
My test fails and throws the exception mentioned in the title above. Please What could be the problem. I am suspecting my EFDContext binding but i dont know how to go about it. I am not sure where i go wrong. Any help would be appreciated.
In the method AddUrl you call the method SaveChanges twice.
To verify this behaviour you need to change:
mockContext.Verify(m => m.SaveChanges(), Times.Once());
Into:
mockContext.Verify(m => m.SaveChanges(), Times.Exactly(2));
You can read about Times options here