Getting exception with Moq when trying to test Task - c#

I'm trying to use Moq (4.10) on async calls but I cannot get the hang of it.
Search on how to do so and found answers which I've tried but I cannot make it to work .
This is my test
public class Test
{
[Fact]
public void Test_Create()
{
var repositoryMock = new Mock<IRepository>();
repositoryMock
.Setup(repo => repo.CreateAsync(It.IsAny<Aggregate >()))
.Returns(Task.CompletedTask);
/// also tried this
/// => .Returns(Task.FromResult(default(object)))
/// and
/// => .Returns(Task.FromResult(false)));
var useCase = new CreateUseCase(repositoryMock.Object);
Task.Run(async () => { await useCase.HandleAsync(new CreateRequest()); });
repositoryMock.VerifyAll();
}
}
resources
How can I tell Moq to return a Task?
Getting this exception
Moq.MockException: 'The following setups on mock
'Mock<.Repository.IRepository:00000001>' were not matched: IRepository
repo => repo.CreateAsync(It.IsAny < Aggregate>())
The repo looks like this
public interface IRepository
{
Task CreateAsync(Aggregate aggregate);
}
The UseCase
public class CreateUseCase : IUseCaseHandler<CreatRequest>
{
private IRepository _repository;
public CreateUseCase (IRepository repository)
{
_repository= repository?? throw new System.ArgumentNullException(nameof(repository));
}
public async Task HandleAsync(CreateRequest request, CancellationToken? cancellationToken = null)
{
Aggregate aggregate = new Aggregate();
aggregate.Create();
await _repository.CreateAsync(aggregate);
}
}
The Repository
public sealed class OrderRepository : ProxyRepository<OrderAggregate>, IOrderRepository
{
public OrderRepository(IUnitOfWork unitOfWork, INotificationDispatcher eventHandler)
: base(unitOfWork, eventHandler)
{
}
async Task IRepository.CreateAsync(Aggregate aggregate)
{
await base.AddAsync(aggregate);
}
}
What is it that I'm doing wrong or missing ?

We normally do not have to mock a method of an interface which doesn't return any unless I'm missing something in your question.
public class CreateUseCaseTests
{
[Fact]
public async Task HandleAsync_ShouldCreateRequest()
{
// Arrange
var repositoryMock = new Mock<IRepository>();
var sut = new CreateUseCase(repositoryMock.Object);
// Act
await sut.HandleAsync(new CreateRequest());
// Assert
repositoryMock.Verify(x => x.CreateAsync(It.IsAny<Aggregate>()), Times.Once);
}
}

I don't think your problem is with the Moq setup at all. The problem is that the unit test runs the meaningful code using Task.Run(), which spawns off a new thread. Then back on the original thread, you immediately test whether the Moq setup has been fulfilled. Since the code under test is launched on a different thread, there is a very real chance that the test for success comes before the code under test is executed.
You should change your unit test to run the test method using async & await, rather than spinning off a new thread. Note that the signature of the test case changes from void to async Task, and we await the code we're testing.
public class Test
{
[Fact]
public async Task Test_Create()
{
var repositoryMock = new Mock<IRepository>();
repositoryMock
.Setup(repo => repo.CreateAsync(It.IsAny<Aggregate >()))
.Returns(Task.CompletedTask);
var useCase = new CreateUseCase(repositoryMock.Object);
await useCase.HandleAsync(new CreateRequest());
repositoryMock.VerifyAll();
}
}

Related

Get an error when verify the mock test in asp dot net core

private Mock<Icache<string>> _mockobj;
[TestInitialize]
public void Initialize()
{
_mockobj = new Mock<Icache<string>>();
}
[TestMethod]
public async Task methodName()
{
_mockobj.Setup(x => x.get("keyname", out id)).Returns(true);
_mockobj.Verify(x => x.get("keyname", out id), Times.Once());
}
Got an error on the verify statement the error is
Evaluation of method System.Linq.Expressions.Expression.Call requires calling method System.RuntimeType.get_IsCollectible
, which cannot be called in this context.
For the sake of brevity let's suppose we have the following stuffs:
public interface ICache<T>
{
void Get(string key, out T value);
}
class SystemUnderTest
{
private readonly ICache<string> cache;
public SystemUnderTest(ICache<string> cache)
=> this.cache = cache;
public void MethodUnderTest()
=> cache.Get("key", out var _);
}
So, the SystemUnderTest (SUT) class receives an ICache instance via constructor and uses it inside its MethodUnderTest.
Then your should look something like this:
//Arrange
var cacheMock = new Mock<ICache<string>>();
var expectedOutValue = "value";
cacheMock.Setup(c => c.Get("key", out expectedOutValue));
//Act
var sut = new SUT(cacheMock.Object);
sut.MethodUnderTest();
//Assert
cacheMock.Verify(c => c.Get("key", out expectedOutValue));
In the Arrange phase we setup the mock
In the Act phase we connect the mock and the SUT, then we call the method which uses the mock
Finally in the Assert phase we verify the usage of the mock

How convert from Moq to NSubstitute that code?

Moq:
var someService = new Mock<ISomeService>();
var data = new ...;
someService.Setup(x => x.UpdateAsync(It.IsAny<Action<OneClass, TwoClass>>()))
.Callback<Action<OneClass, TwoClass>>((func) =>
{
func(data);
})
.Returns(Task.CompletedTask);
UpdateAsync have action (first parameter).
I want to execute action.
I tried
someService
.UpdateAsync(Arg.Do<Action<OneClass, TwoClass>>(x => x(data)))
.Returns(Task.CompletedTask);
but it didn`t work.
How is this done using NSubstitute?
You have an action that takes two arguments yet try to invoke it using only one
The following example test verifies the expected behavior and that the mocking framework does in fact behave as expected.
[TestClass]
public class MyTestClass {
[TestMethod]
public async Task Should_Invoke_Callback() {
//Arrange
var someService = Substitute.For<ISomeService>();
OneClass one = new OneClass();
TwoClass two = new TwoClass();
someService
.UpdateAsync(Arg.Do<Action<OneClass, TwoClass>>(action => action(one, two)))
.Returns(Task.CompletedTask);
bool invoked = false;
Action<OneClass, TwoClass> callback = (a, b) => {
invoked = a != null && b != null;
};
//Act
await someService.UpdateAsync(callback);
//Assert - using FluentAssertions
invoked.Should().BeTrue();
}
}
public class TwoClass {
}
public class OneClass {
}
public interface ISomeService {
Task UpdateAsync(Action<OneClass, TwoClass> action);
}
Reference Actions with argument matchers

I want to write a test that will definitely tell if the mock-method was called

I have a method:
public class CreateNewAccountUseCase
{
private readonly IAccountRepository _accountRepository;
public CreateNewAccountUseCase(IAccountRepository accountRepository)
{
_accountRepository = accountRepository;
}
public virtual async Task Execute(Account account)
{
await _accountRepository.Create(account);
}
}
I use it in the controller:
public async Task<ActionResult<AccountModel>> CreateAccount([FromBody]CreatingAccount creatingAccount)
{
var account = creatingAccount.ConvertToAccount();
await _createNewAccountUseCase.Execute(account);
return Created($"/accounts/{account.Id}", account);
}
I want to be sure that the UseCase method will be exactly called.
I wrote this controller test:
[Fact]
public async Task Create()
{
// arrange
var account = new CreatingAccount();
var accountRepository = new Mock<IAccountRepository>();
var createNewAccountUseCase = new Mock<CreateNewAccountUseCase>(accountRepository.Object);
createNewAccountUseCase.Setup(m => m.Execute(account)).Returns(Task.CompletedTask);
// act
await controller.CreateAccount(account);
// assert
createNewAccountUseCase.Verify(m => m.Execute(account), Times.Once);
}
I expect createNewAccountUseCase.Verify() to check if the method has been method but I get failed test with a message:
Moq.MockException :
Expected invocation on the mock once, but was 0 times: m => m.Execute(account)
Performed invocations:
Mock<CreateNewAccountUseCase:1> (m):
No invocations performed.
How do I make sure the method (createNewAccountUseCase.Verify()) is called?
You are mocking the subject under test. Instead mock the dependency and invoked the method under test
[Fact]
public async Task Create() {
// arrange
var account = new CreatingAccount();
var accountRepository = new Mock<IAccountRepository>();
accountRepository.Setup(m => m.Create(It.IsAny<Account>())).Returns(Task.CompletedTask);
var createNewAccountUseCase = new CreateNewAccountUseCase(accountRepository.Object);
// act
await createNewAccountUseCase.Execute(account.ConvertToAccount());
// assert
accountRepository.Verify(m => m.Create(It.IsAny<Account>()), Times.Once);
}
The assertion can then be done on the repository mock to verify that the method behaves as expected.
In the controller test of your question you could have used the mock use case but your also need to make sure that it was injected into the controller.
But your example showed no such injection.
The following example creates the controller and explicitly injects the dependency
[Fact]
public async Task Create() {
// arrange
var account = new CreatingAccount();
var accountRepository = new Mock<IAccountRepository>();
accountRepository.Setup(m => m.Create(It.IsAny<Account>())).Returns(Task.CompletedTask);
var createNewAccountUseCase = new CreateNewAccountUseCase(accountRepository.Object);
var controller = new MyController(createNewAccountUseCase);
// act
await controller.CreateAccount(account);
// assert
accountRepository.Verify(m => m.Create(It.IsAny<Account>()), Times.Once);
}

Delay in Moq return for async method not delaying

In my unit test, I'm trying to mock out the Run() async method from my interface IPipeline and simulate a delay, where it is called in the class PipelineScheduler
public interface IPipeline
{
Task Run();
}
Test Moq:
[SetUp]
public void SetUp()
{
_mockPipeline = new Mock<IPipeline>();
_mockPipeline.Setup(x => x.Run()).Returns(async () =>
{
await Task.Delay(3000);
});
_scheduler = new PipelineScheduler(_mockPipeline.Object);
}
However when I run the test and debug where the mocked method is called
await _pipeline.Run().ConfigureAwait(false);
there is no delay and execution continues after this line immediately.
But if I replace the mock with a stub class, the delay works fine.
private class MockPipeline : IPipeline
{
public async Task Run()
{
await Task.Delay(3000);
}
}
[SetUp]
public void SetUp()
{
_mockPipeline = new MockPipeline();
_scheduler = new PipelineScheduler(_mockPipeline);
}
So I suppose the question is what's different from how I'm creating the delay with moq vs my stubbed class?
The difference is that the setup is being configured incorrectly.
Returning a Task i.e:.Returns(Task.Delay(3000)); is all that is needed for the the setup to behave a desired. The previous setup is a fire and forget async void which is why the previous example did not wait and continued immediately.
The following minimal example demonstrates how the mock should have been setup
[TestClass]
public class MyTestClass {
[TestMethod]
public async Task MyTestMethod() {
//Arrange
var _mockPipeline = new Mock<IPipeline>();
_mockPipeline.Setup(x => x.Run()).Returns(Task.Delay(3000)).Verifiable();
var sut = new PipelineScheduler(_mockPipeline.Object);
//Act
await sut.MethodUnderTest();
//Assert
_mockPipeline.Verify();
}
}
public interface IPipeline {
Task Run();
}
public class PipelineScheduler {
private IPipeline _pipeline;
public PipelineScheduler(IPipeline pipeline) {
this._pipeline = pipeline;
}
public async Task MethodUnderTest() {
await _pipeline.Run().ConfigureAwait(false);
}
}
When exercised, the test delays for the configured 3 seconds.
An old question but I just had the problem and the correct way is not the accepted answer. The correct way is to use a function in the return.
i.e.
.Returns(() => Task.Delay(3000))
Without the () =>, the Delay is only applied once, even if you do multiple sequential calls, for example, like if you did this :
await _pipeline.Run().ConfigureAwait(false);
await _pipeline.Run().ConfigureAwait(false);
await _pipeline.Run().ConfigureAwait(false);
See this reproduction on dotnetfiddle.net

How to unit test RelayCommand that Executes an async method?

As there is no RelayCommandAsync (at least not that I know of), how to test this scenario. For example:
public RelayCommand LoadJobCommand
{
get
{
return this.loadJobCommand ?? (
this.loadJobCommand =
new RelayCommand(
this.ExecuteLoadJobCommandAsync));
}
}
private async void ExecuteLoadJobCommandAsync()
{
await GetData(...);
}
Test:
vm.LoadJobCommand.Execute()
Assert.IsTrue(vm.Jobs.Count > 0)
It really depends on what you are trying to test:
Test that the RelayCommand is properly hooked up and calls your async
method?
or
Test that the Async Method logic is correct?
1. Testing the RelayCommand trigger
1.a Using External Dependencies to verify
From my personal experience the easiest way to test that the trigger is wired up correctly to execute the command and then test that your class has interacted with another external class somewhere as expected. E.g.
private async void ExecuteLoadJobCommandAsync()
{
await GetData(...);
}
private async void GetData(...)
{
var data = await _repo.GetData();
Jobs.Add(data);
}
Its fairly easy to test that your repo gets called.
public void TestUsingExternalDependency()
{
_repo.Setup(r => r.GetData())
.Returns(Task.Run(() => 5))
.Verifiable();
_vm.LoadJobCommand.Execute(null);
_repo.VerifyAll();
}
I sometimes even do this, so that it doesn't try to process everything:
[Test]
public void TestUsingExternalDependency()
{
_repo.Setup(r => r.GetData())
.Returns(() => { throw new Exception("TEST"); })
.Verifiable();
try
{
_vm.LoadJobCommand.Execute(null);
}
catch (Exception e)
{
e.Message.Should().Be("TEST");
}
_repo.VerifyAll();
}
1.b Using a Scheduler
Another option is to use a scheduler, and schedule tasks using that.
public interface IScheduler
{
void Execute(Action action);
}
// Injected when not under test
public class ThreadPoolScheduler : IScheduler
{
public void Execute(Action action)
{
Task.Run(action);
}
}
// Used for testing
public class ImmediateScheduler : IScheduler
{
public void Execute(Action action)
{
action();
}
}
Then in your ViewModel
public ViewModelUnderTest(IRepository repo, IScheduler scheduler)
{
_repo = repo;
_scheduler = scheduler;
LoadJobCommand = new RelayCommand(ExecuteLoadJobCommandAsync);
}
private void ExecuteLoadJobCommandAsync()
{
_scheduler.Execute(GetData);
}
private void GetData()
{
var a = _repo.GetData().Result;
Jobs.Add(a);
}
And your test
[Test]
public void TestUsingScheduler()
{
_repo.Setup(r => r.GetData()).Returns(Task.Run(() => 2));
_vm = new ViewModelUnderTest(_repo.Object, new ImmediateScheduler());
_vm.LoadJobCommand.Execute(null);
_vm.Jobs.Should().NotBeEmpty();
}
2. Testing the GetData Logic
If you are looking to test get GetData() logic or even the ExecuteLoadJobCommandAsync() logic. Then you should definitely make the method you want to test, as Internal, and mark your assmebly as InternalsVisibleTo so that you can call those methods directly from your test class.
Why don't you cover GetData(...) method with tests? I don't see any sense in testing relay commands
I was not using async/await but I have run in to a similar problem in the past. The situation I was in is the method called a Task.Run( inside of itself and the unit test was verifying that the ViewModel was calling the service with the correct number of times with the correct parameters.
The way we solved this was we had our Mock of the service that was being called use a ManualResetEventSlim, then the unit test waited for that reset event to be called before proceeding.
[TestMethod]
public void EXAMPLE()
{
using (var container = new UnityAutoMoqContainer())
{
//(SNIP)
var serviceMock = container.GetMock<ITreatmentPlanService>();
var resetEvent = new ManualResetEventSlim();
serviceMock.Setup(x=>x.GetSinglePatientViewTable(dateWindow, currentPatient, false))
.Returns(() =>
{
resetEvent.Set();
return new ObservableCollection<SinglePatientViewDataRow>();
});
var viewModel = container.Resolve<SinglePatientViewModel>();
//(SNIP)
viewModel.PatientsHadTPClosed(guids, Guid.NewGuid());
waited = resetEvent.Wait(timeout);
if(!waited)
Assert.Fail("GetSinglePatientViewTable was not called within the timeout of {0} ms", timeout);
//(SNIP)
serviceMock.Verify(x => x.GetSinglePatientViewTable(dateWindow, currentPatient, false), Times.Once);
}
}
If this approach works or not for you all depends on what your unit test is actually testing. Because you check Assert.IsTrue(vm.Jobs.Count > 0) it looks like you have extra logic that is being done after the await GetData(...); call, so this might not be applicable for your current problem. However, this may be helpful for other unit tests you need to write for your view model.

Categories