How to Tell Moq to Return a Task

How can I tell Moq to return a Task?

Your method doesn't have any callbacks so there is no reason to use .CallBack(). You can simply return a Task with the desired values using .Returns() and Task.FromResult, e.g.:

MyType someValue=...;
mock.Setup(arg=>arg.DoSomethingAsync())
.Returns(Task.FromResult(someValue));

Update 2014-06-22

Moq 4.2 has two new extension methods to assist with this.

mock.Setup(arg=>arg.DoSomethingAsync())
.ReturnsAsync(someValue);

mock.Setup(arg=>arg.DoSomethingAsync())
.ThrowsAsync(new InvalidOperationException());

Update 2016-05-05

As Seth Flowers mentions in the other answer, ReturnsAsync is only available for methods that return a Task<T>. For methods that return only a Task,

.Returns(Task.FromResult(default(object)))

can be used.

As shown in this answer, in .NET 4.6 this is simplified to .Returns(Task.CompletedTask);, e.g.:

mock.Setup(arg=>arg.DoSomethingAsync())        
.Returns(Task.CompletedTask);

How to return a Taskstring using Moq?

Use Task.FromResult(expected)

mock.Setup(arg => arg.GetScoreByTotalWeighting(value)).Returns(Task.FromResult(expected))

also I'd recomend to avoid value as parameter, when you dont care about that paramter when returning result. You can use It.IsAny<int>(), like that:

mock.Setup(arg => arg.GetScoreByTotalWeighting(It.IsAny<int>())).Returns(Task.FromResult(expected))

Problem that you setting up mock.Setup(arg => arg.GetScoreByTotalWeighting(value)) with value == 0 and then call survey.GetResult(score) with 50. Use It.IsAny<int>() at both places to avoid that problem, or pass same value:

mock.Setup(arg => arg.GetScoreByTotalWeighting(score))

Solution:

public async Task GetResult()
{
//Arrange
string expected = "test";

var mock = new Mock<IRetreiveQuestionRepository>();
mock.Setup(arg => arg.GetScoreByTotalWeighting(It.IsAny<int>()))
.ReturnsAsync(expected);
var survey = new SurveyResult(mock.Object);

//Act
string result = await survey.GetResult(It.IsAny<int>());

//Assert
Assert.Equal(expected, result);
}

Return Task with moq

Thanks to Liam and CodeCaster.

Seems like there is no need for incompleted Tasks. Works fine with mocking up with Task.FromResult();

Something like

var sourceDto = new SourceOneDto {data: "one"};
_sourceServiceMock.Setup(s => s.ReturnA()).Returns(Task.FromResult(sourceDto));

//This might work as well
_sourceServiceMock.Setup(s => s.ReturnA()).ReturnsAsync(sourceDto);

Moq Framework to unit test a method that returns a task

Mock returns false, because when you call HttpPost parameters don't match with ones that were set up. The second parameter is different.

You can set up mock like that:

mock
.Setup(x => x.HttpPost("http://test.com", It.IsAny<StringContent>(), "token"))
.Returns(Task.FromResult(true)); //or .ReturnsAsync(true);

It tells mocking framework, that second parameter can be any object of type StringContent.

Docs can be found here: https://github.com/Moq/moq4/wiki/Quickstart#matching-arguments

Moq with Task await

DoSomething returns null instead of returning a Task, and so you get an exception when awaiting it. You need to specify when building the mock that it should return a Task.

In this case it seems that you can simply return an already completed task using Task.FromResult so the mock setup should look like this:

this._mockService.Setup(...).Returns(Task.FromResult(false));

Beginning with the next version of .Net (4.6) you can use Task.CompletedTask like this:

this._mockService.Setup(...).Returns(Task.CompletedTask);

How do I setup an async method which only returns a Task in strict mode in Moq 4.13.1?

A Task is still needed to allow the await to flow to completion when exercising the test.

So it needs to be setup to return a Task.

Task.CompletedTask can be used for this

//...

_service
.Setup(m => m.IReturnATask(It.Any<Guid>()))
.Returns(Task.CompletedTask);

//...

How to mock which return type is 'async Task(IListModelClass, PaginationModel)'?

The methods of the It class, like Is or IsAny, should be used only inside the Setup method.

They help you specify when your mock should "trigger".

If your method returns with a Task then you have several options

ReturnAsync

var expectedJobLicensePaths = ...;
var expectedPaginationModel = ...;

mockIJobLicensePathService
.Setup(x => x.GetJobPathByFilters(It.IsAny<PathSearch>()))
.ReturnsAsync((expectedJobLicensePaths, expectedPaginationModel));

Result + Return

Since 4.16 you can rewrite the above setup to this

var expectedJobLicensePaths = ...;
var expectedPaginationModel = ...;

mockIJobLicensePathService
.Setup(x => x.GetJobPathByFilters(It.IsAny<PathSearch>()).Result)
.Returns((expectedJobLicensePaths, expectedPaginationModel));

How to filter by an expression when mocking a repository with Moq

Let's start with the basics:

  • Dummy: simple code that returns bogus data
  • Fake: a working alternative which can take shortcuts
  • Stub: custom logic with predefined data
  • Mock: custom logic with expectations (interactive stub)
  • Shim: custom logic at run-time (replace static with a delegate)
  • Spy: interceptors to record calls

So, your mock is an interactive stub which means it can return different outputs based on the received input. In your Setup call you have made the following statement: whatever I receive as a filter expression I should always return with the entire list

If you want to apply the filter then change your setup

.Setup(x => x.GetAsync(It.IsAny<Expression<Func<Airline, bool>>>()))
.ReturnsAsync(filter => GetTestAirlines.Where(filter));

Now if you assert on airlineDtoList.Count then it will return 2. But in this case you are not testing the GetAllAsync function rather than your mock.

So, I would rather spend more time testing the // some logic


You can also take advantage of async-await in your test

[Fact]
public Task AirlineService_GetAll_ReturnsAirlines()
{
//Arrange
var mockAirlineRepo = new MockAirlineRepository().MockGetAll();
var airlineService = new AirlineService(mockAirlineRepo.Object, _airlineMapper);

//Act
var response = await airlineService.GetAllAsync();
var result = response.Data;

//Assert
...
}

XUnit Test Moq failing

The problem is because you are returning a fixed value

_mockRepo.Setup(x => x.CountAsync()).ReturnsAsync(list.Count);

The above is the same as

_mockRepo.Setup(x => x.CountAsync()).ReturnsAsync(7);

it will return 7 every time since it was setup with a fixed value.

Use a function/delegate that will be invoked every time the expected member is called.

[Fact]
public async Task ServerAccess_Created() {
var list = MockData.GetServerAccessList(); // 7 test records

_mockRepo
.Setup(x => x.CountAsync())
.ReturnsAsync(() => list.Count); //delegate invoked each time

_mockRepo
.Setup(x => x.Add(It.IsAny<ServerAccess>()))
.Callback(ServerAccess item => list.Add(item)); //delegate invoked each time

_mockUnitOfWork
.Setup(x => x.Repository<ServerAccess>())
.Returns(_mockRepo.Object); //fixed value

int before = await _mockRepo.Object.CountAsync();

CreateHandler sut = new CreateHandler(_mockUnitOfWork.Object);

await sut.Execute(new CreateCommand() {
AccessMethod = "New server access method",
Description = "New description"
});

int after = await _mockRepo.Object.CountAsync();

// Assert
Assert.True(after == 8);
}

However, the above test should be simplified to assert the actual expected behavior based on the subject under test

[Fact]
public async Task ServerAccess_Created() {
//Arrange
_mockUnitOfWork
.Setup(x => x.Repository<ServerAccess>())
.Returns(_mockRepo.Object);

CreateHandler sut = new CreateHandler(_mockUnitOfWork.Object);

//Act
await sut.Execute(new CreateCommand() {
AccessMethod = "New server access method",
Description = "New description"
});

// Assert
_mockRepo.Verify(x => x.Add(It.IsAny<ServerAccess>());
}

Using Moq to mock an asynchronous method for a unit test

You're creating a task but never starting it, so it's never completing. However, don't just start the task - instead, change to using Task.FromResult<TResult> which will give you a task which has already completed:

...
.Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK)));

Note that you won't be testing the actual asynchrony this way - if you want to do that, you need to do a bit more work to create a Task<T> that you can control in a more fine-grained manner... but that's something for another day.

You might also want to consider using a fake for IHttpClient rather than mocking everything - it really depends on how often you need it.



Related Topics



Leave a reply



Submit