Sono abbastanza familiare con il modello asincrono/atteso, ma mi imbatto in un comportamento che mi sembra strano. Sono sicuro che c'è una ragione perfettamente valida per cui sta accadendo, e mi piacerebbe capire il comportamento.Comportamento imprevisto quando si passano azioni asincrone attorno a
Lo sfondo qui è che sto sviluppando un'app di Windows Store, e dal momento che sono uno sviluppatore cauto e coscienzioso, sono un'unità che testa tutto. Ho scoperto abbastanza rapidamente che lo ExpectedExceptionAttribute
non esiste per i WSA. Strano, vero? Bene, nessun problema! Posso più o meno replicare il comportamento con un metodo di estensione! Così ho scritto questo:
public static class TestHelpers
{
// There's no ExpectedExceptionAttribute for Windows Store apps! Why must Microsoft make my life so hard?!
public static void AssertThrowsExpectedException<T>(this Action a) where T : Exception
{
try
{
a();
}
catch (T)
{
return;
}
Assert.Fail("The expected exception was not thrown");
}
}
Ed ecco, funziona magnificamente.
Così ho continuato felicemente a scrivere i miei test di unità, fino a quando non ho premuto un metodo asincrono che volevo confermare genera un'eccezione in determinate circostanze. "Nessun problema", pensai tra me e me, "posso passare in un lambda asincrono!"
Così ho scritto questo metodo di prova:
[TestMethod]
public async Task Network_Interface_Being_Unavailable_Throws_Exception()
{
var webManager = new FakeWebManager
{
IsNetworkAvailable = false
};
var am = new AuthenticationManager(webManager);
Action authenticate = async() => await am.Authenticate("foo", "bar");
authenticate.AssertThrowsExpectedException<LoginFailedException>();
}
Questo, a sorpresa, getta un errore di runtime. In realtà si blocca il test-runner!
ho fatto un sovraccarico del mio AssertThrowsExpectedException
metodo:
public static async Task AssertThrowsExpectedException<TException>(this Func<Task> a) where TException : Exception
{
try
{
await a();
}
catch (TException)
{
return;
}
Assert.Fail("The expected exception was not thrown");
}
e ho ottimizzato la mia prova:
[TestMethod]
public async Task Network_Interface_Being_Unavailable_Throws_Exception()
{
var webManager = new FakeWebManager
{
IsNetworkAvailable = false
};
var am = new AuthenticationManager(webManager);
Func<Task> authenticate = async() => await am.Authenticate("foo", "bar");
await authenticate.AssertThrowsExpectedException<LoginFailedException>();
}
Io sto bene con la mia soluzione, sto solo chiedendo esattamente perché tutto va a forma di pera quando provo a invocare il async Action
. Sto indovinando perché, per quanto riguarda il runtime, è non e uno Action
, sto solo stipando il lambda dentro. So che Lambda sarà felicemente assegnata a Action
o Func<Task>
.
Nei test di Windows Store, utilizzare 'Assert.ThrowsException', che ([come da VS2012 Update 2] (http://support.microsoft.com/kb/2797912)) supporta 'asdd' lambda. Si noti che 'Action' è un metodo * sincrono * senza un valore di ritorno, mentre' Func 'è un metodo * asincrono * senza un valore di ritorno. –
Ooh, non ho notato "Assert.ThrowsException". Passerò i miei test per usarlo. –