2012-08-22 8 views
25

Pracuję nad konwertowaniem treści synchronicznego kodu asp.net do .net 4.5 i nowej składni asynchronicznej.Konwersja synchronicznych makr Moq na asynchroniczne

mam dużo kodu testu, który wygląda tak:

var retVal = new Foo(bar,baz); 
_myMock.Setup(x => x.DoSomething(123)).Returns(retVal); 

Kiedy przekonwertować podpis doSomething z Foo DoSomething() do async Task<Foo> DoSomething(), wszystkie moje kodu testu musi być przepisany. Mój obecny obejście jest przekształcenie oryginalnego kodu coś jak:

var retVal = new Foo(bar,baz); 
_myMock.Setup(x => x.DoSomething(123)) 
    .Returns(new Task<Foo>(()=>retVal)); 

Nie jest to szczególnie trudne przekształcić, ale jest to uciążliwe, gdy mam tysiące testów, które muszą być aktualizowane.

Próbowałem utworzyć metodę rozszerzenia o nazwie ReturnsAsync, aby wykonać niektóre z tych formularzy m, ale miałem pewne problemy z typem interferencji, których nie mogłem w pełni wyjaśnić. Czy istnieje standardowy lub łatwiejszy sposób na konwersję tego rodzaju prób, aby lepiej obsługiwać metodę asynchroniczną?

Odpowiedz

20

Moq 4.2 dodaje metodę ReturnsAsync() wewnętrzny, więc nie trzeba już dodawać własne.

34

Po pierwsze, nazewnictwo: Asynchroniczny wzorzec oparty na zadaniach (TAP) mówi, że wszystkie metody asynchroniczne i zwracające Task powinny mieć nazwę o nazwie kończącej się na Async. Twoja metoda powinna więc mieć nazwę: DoSomethingAsync.

Po drugie, konstruktor z Task tworzy Task, który nie został uruchomiony, musisz to zrobić ręcznie. Jeśli twoja rzeczywista metoda DoSomething również to robi, to znowu nie działa zgodnie z protokołem TAP, a to oznacza, że ​​twój kod nie będzie działał dobrze z await. Zamiast tego powinieneś użyć Task.Run(() => value) lub, jeszcze lepiej, Task.FromResult(value).

Po trzecie, byłoby lepiej, gdybyś pokazał nam swój kod, który nie działał dobrze, abyśmy mogli powiedzieć, gdzie popełniłeś błąd.

Ciało metody rozszerzenia ReturnsAsync() jest dość proste, ale większość pracy dla mnie polegała na wykreśleniu poprawnych typów (zwłaszcza, że ​​nie znam Moqa). Kod wygląda następująco:

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