методы Async возвращают null

17

Если я попытаюсь высмеять тип, содержащий метод async , например:

interface Foo
{
    Task<int> Bar();
}

Затем метод Bar mock возвращает null. Я думаю, что Moq выбирает default(Task<int>) в качестве возвращаемого значения по умолчанию для моего метода, который действительно null . Однако Moq должен скорее выбрать что-то вроде Task.FromResult(default(int)) как значение по умолчанию. Могу ли я заставить Moq использовать методы async, возвращающие ненулевые задачи?

    
задан Simon V. 09.05.2013 в 02:04
источник

4 ответа

33

Если кто-то заинтересован, я сделал класс расширения, который делает методы асинхронизации более узкими:

public static class SetupExtensions
{
    public static IReturnsResult<TMock> ReturnsTask<TMock, TResult>(
        this ISetup<TMock, Task<TResult>> setup) where TMock : class
    {
        return setup.Returns(() => Task.FromResult(default(TResult)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, TResult>(
        this ISetup<TMock, Task<TResult>> setup, TResult value) where TMock : class
    {
        return setup.Returns(() => Task.FromResult(value));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, TResult>(
        this ISetup<TMock, Task<TResult>> setup, Func<TResult> func) where TMock : class
    {
        return setup.Returns(Task.Factory.StartNew(func));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, T, TResult>(
        this ISetup<TMock, Task<TResult>> setup, Func<T, TResult> func) where TMock : class
    {
        return setup.Returns<T>(arg => Task.Factory.StartNew(() => func(arg)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, TResult>(
        this ISetup<TMock, Task<TResult>> setup, Func<T1, T2, TResult> func) where TMock : class
    {
        return setup.Returns<T1, T2>((arg1, arg2) => Task.Factory.StartNew(() => func(arg1, arg2)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, T3, TResult>(
        this ISetup<TMock, Task<TResult>> setup, Func<T1, T2, T3, TResult> func) where TMock : class
    {
        return setup.Returns<T1, T2, T3>((arg1, arg2, arg3) => Task.Factory.StartNew(() => func(arg1, arg2, arg3)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, T3, T4, TResult>(
        this ISetup<TMock, Task<TResult>> setup, Func<T1, T2, T3, T4, TResult> func) where TMock : class
    {
        return setup.Returns<T1, T2, T3, T4>((arg1, arg2, arg3, arg4) => Task.Factory.StartNew(() => func(arg1, arg2, arg3, arg4)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock>(this ISetup<TMock, Task> setup, Action action) where TMock : class
    {            
        return setup.Returns(Task.Factory.StartNew(action));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, T>(this ISetup<TMock, Task> setup, Action<T> action) where TMock : class
    {            
        return setup.Returns<T>(arg => Task.Factory.StartNew(() => action(arg)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2>(this ISetup<TMock, Task> setup, Action<T1, T2> action) where TMock : class
    {            
        return setup.Returns<T1, T2>((arg1, arg2) => Task.Factory.StartNew(() => action(arg1, arg2)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, T3>(this ISetup<TMock, Task> setup, Action<T1, T2, T3> action) where TMock : class
    {            
        return setup.Returns<T1, T2, T3>((arg1, arg2, arg3) => Task.Factory.StartNew(() => action(arg1, arg2, arg3)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, T3, T4>(this ISetup<TMock, Task> setup, Action<T1, T2, T3, T4> action) where TMock : class
    {            
        return setup.Returns<T1, T2, T3, T4>((arg1, arg2, arg3, arg4) => Task.Factory.StartNew(() => action(arg1, arg2, arg3, arg4)));
    }

    public static IReturnsResult<TMock> ReturnsTask<TMock>(this ISetup<TMock, Task> setup) where TMock : class
    {
        return setup.Returns(Task.Factory.StartNew(delegate {  }));
    }
}

Некоторые примеры:

//Example 1 :
public interface IFoo
{
    Task Bar();
}

var mock = new Mock<IFoo>();

mock.Setup(m => m.Bar()).ReturnsTask(); //await Bar() will return void

//Example 2 :
public interface IFoo
{
    Task<int> Bar();
}

var mock = new Mock<IFoo>();

mock.Setup(m => m.Bar()).ReturnsTask(); //await Bar() will return default(int)

//Example 3 :
public interface IFoo
{
    Task<int> Bar();
}

var mock = new Mock<IFoo>();

mock.Setup(m => m.Bar()).ReturnsTask(4); //await Bar() will return 4;

//Example 4 :
public interface IFoo
{
    Task<int> Bar(int x, int y);
}

var mock = new Mock<IFoo>();

mock.Setup(m => m.Bar(It.IsAny<int>(), It.IsAny<int>()))
                     .ReturnsTask<IFoo, int, int, int>((x,y) => x + y); //await Bar(x, y) will return x + y;
    
ответ дан Simon V. 09.05.2013 в 14:55
источник
  • Эпически полезно. Благодаря :-) –  Jon Rea 01.08.2013 в 16:44
  • Это блестяще работает –  Ian1971 10.10.2013 в 16:55
5

Вам просто нужно заглушить метод Bar и заставить его возвращать Task.FromResult(default(int))

    
ответ дан aquaraga 09.05.2013 в 02:13
источник
3

Похоже, эта проблема исправлена ​​ в Moq 4.2. Таким образом, вам просто нужно перейти на новейшую версию Moq (по крайней мере, он начал возвращать непустые задачи в моем случае)

    
ответ дан avitenberg 22.07.2014 в 16:37
источник
1

Напомним, что структура Moq является открытым исходным кодом. В базе кода (доступно здесь ) мы видим, что когда вызов метода, который не был установлен выполняется, возвращаемое значение является результатом частного поля valueDel в классе MethodCallReturn<TMock, TResult> . Это поле создается таким образом, чтобы оно возвращало значение по умолчанию для типа результата:

 private Delegate valueDel = (Func<TResult>)(() => default(TResult));

Вы можете добавить метод, который бы переопределял значение по умолчанию для заданного типа, возвращаемого из Mock, или явно возвратил предложенное значение по умолчанию в случае Task .

Вы также можете указать проблему на странице страницы со списком ошибок.

Не имея дело с источником Moq, вам нужно просто заглушить интерфейс Foo , как предложил акварага. Быстрое объяснение различий между mocks и stubs можно найти здесь .

    
ответ дан Ben Reich 09.05.2013 в 03:58
источник