2013-05-09 16 views
17

Se provo prendere in giro un tipo contenente un metodo async quali:metodi asincroni restituiscono null

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

Poi metodo del finto Bar sta tornando nullo. Immagino che Moq stia scegliendo default(Task<int>) come valore di ritorno predefinito per il mio metodo, che in effetti è null. Tuttavia Moq dovrebbe piuttosto scegliere qualcosa come Task.FromResult(default(int)) come valore predefinito. Posso forzare Moq affinché i metodi asincroni restituiscano attività non nulle?

risposta

33

Se qualcuno è interessato, ho fatto una classe di estensione che rende i metodi asincroni STUBING meno prolissa:

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 { })); 
    } 
} 

Alcuni esempi:

//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; 
+1

Epicely utile. Grazie :-) –

+0

Questo funziona brillantemente – Ian1971

5

Sarà sufficiente a stub il metodo bar, e farla tornare Task.FromResult(default(int))

1

Ricordiamo che il quadro Moq è open source. Nella base di codice (disponibile here), possiamo vedere che quando viene eseguita una chiamata di metodo che non è stata impostata, il valore di ritorno è il risultato del campo privatonella classe MethodCallReturn<TMock, TResult>. Questo campo è un'istanza in modo che restituisca il valore di default del tipo di risultato:

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

Si potrebbe aggiungere un metodo che sarebbe ignorare il valore predefinito per un determinato tipo che viene restituito da un Mock, o esplicitamente restituire la tua suggerito come predefinito nel caso Task.

È inoltre possibile presentare un problema su Moq issues list page.

Se non si ha a che fare con la sorgente Moq, tuttavia, è sufficiente interrompere l'interfaccia Foo, come suggerito da aquaraga. Una rapida spiegazione della differenza tra mock e stub può essere trovata here.

3

Sembra che questo problema è in fixed Moq 4.2. Quindi è sufficiente eseguire l'aggiornamento alla versione più recente di Moq (almeno ha iniziato a restituire Attività non vuote nel mio caso)

Problemi correlati