andrey.shedko
andrey.shedko

Reputation: 3238

Moq WebApi async method

I'm new to testing with Moq, so I'm confused a bit regarding ReturnsAsync. Here is my test method, where I'm expecting ReturnsAsync should receive type that will be returned by method defined in Setup. Am I right?

But seemed ReturnsAsync should have the other signature - it's looking for Func delegate.

[TestClass]
public class TourObjectControllerTest
{
    [TestMethod]
    public async Task GetTourObjects()
    {
        var mockService = new Mock<ITourObjectService>(MockBehavior.Default);
        mockService.Setup(x => x.GetAll()).ReturnsAsync(new Task<IEnumerable<TourObjectDTO>>);
        var controller = new TourObjectController(mockService.Object);
        var result = await controller.Get();
        Assert.IsNotNull(result);
        Assert.AreSame(typeof(TourObjectViewModel), result);
    }
}

Method under test:

public async Task<IEnumerable<TourObjectViewModel>> Get()
{
    IEnumerable<TourObjectViewModel> viewmodel = null;
    try
    {
        var tourobjects = await _tos.GetAll();
        viewmodel = Mapper.Map<IEnumerable<TourObjectViewModel>>(tourobjects);
    }
    catch (Exception ex)
    {
        Log.ErrorFormat("Method:{0} <br/> Error: {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, ex);
    }
    return viewmodel;
}

Upvotes: 2

Views: 1085

Answers (2)

Nkosi
Nkosi

Reputation: 247551

Pass an actual result.

Assuming ITourObjectService.GetAll() returns Task<IEnumerable<TourObjectDTO>>

eg

[TestClass]
public class TourObjectControllerTest
{
    [TestMethod]
    public async Task GetTourObjects()
    {
        var fakeData = new List<TourObjectDTO>() {
            new TourObjectDTO { ... }
        };
        var mockService = new Mock<ITourObjectService>(MockBehavior.Default);
        mockService.Setup(x => x.GetAll()).ReturnsAsync(fakeData);
        var controller = new TourObjectController(mockService.Object);
        var result = await controller.Get();
        Assert.IsNotNull(result);
        Assert.IsTry(typeof(IEnumerable<TourObjectViewModel>).IsAssignableFrom(result.GetType());
    }
}

Upvotes: 1

Vadim Martynov
Vadim Martynov

Reputation: 8902

ReturnsAsync() should take a return value as the paramter instead of Task<TReurnValue>. For example, next 2 lines of code are equal (by behavior):

mockService.Setup(x => x.GetAll()).ReturnsAsync(new List<TourObjectDTO>());
mockService.Setup(x => x.GetAll()).Returns(Task.FromResult(new List<TourObjectDTO>()));

You need to replace new List<TourObjectDTO>() with your test data which you want to retrieve in the test from the mock. For example, you can create just few test values:

var testData = new [] { new TourObjectDTO(1, "test1"), new TourObjectDTO(2, "test2") };
mockService.Setup(x => x.GetAll()).ReturnsAsync(testData);

or create fake data generator if needed.

Note that 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.

Upvotes: 1

Related Questions