私は async/await パターンにかなり精通していますが、奇妙に感じるいくつかの動作に出くわしています。それが起こっているのには完全に正当な理由があると確信しており、その動作を理解したい.
ここでの背景は、私が Windows ストア アプリを開発しているということです。私は用心深く良心的な開発者であるため、すべてのユニット テストを行っています。ExpectedExceptionAttribute
WSA には が存在しないことがすぐにわかりました。変ですよね?まあ、問題ありません!拡張メソッドを使用して、多かれ少なかれ動作を複製できます! だから私はこれを書いた:
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");
}
}
そして、それは美しく機能します。
そのため、特定の状況下で例外をスローすることを確認したい非同期メソッドにヒットするまで、単体テストを楽しく書き続けました。「問題ありません」と私は思いました。「非同期ラムダを渡すだけでいいのです!」
だから私はこのテスト方法を書いた:
[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>();
}
これは、驚くべきことに、実行時エラーをスローします。それは実際にテストランナーをクラッシュさせます!
AssertThrowsExpectedException
メソッドのオーバーロードを作成しました。
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");
}
そして私は自分のテストを微調整しました:
[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>();
}
私は自分の解決策に問題はありません.asyncを呼び出そうとすると、なぜすべてが洋ナシの形になるのか正確に疑問に思っていAction
ます. ランタイムに関する限り、それは ではなく、Action
ラムダを詰め込んでいるだけだからだと思います。ラムダが喜んでまたはのいずれかに割り当てられることを私は知っていAction
ますFunc<Task>
。