💭
NUnit4の新しい非同期アサートを試してみる
新しい非同期アサートとは
[Test]
public async Task AssertionPasses_CompletedTaskWithResult_EqualsResult()
{
await Assert.ThatAsync(() => Task.FromResult(42), Is.EqualTo(42));
}
上記のようにThatAsyncが実装されている。
これにより、Taskを返すような非同期メソッドをアサートできる。
さらに、ブロック内のアサートをすべて実行させたいときは「Assert.MultipleAsync」が使える。
[Test]
public async Task AssertMultipleAsyncSucceeds()
{
await Assert.MultipleAsync(async () =>
{
await Assert.ThatAsync(() => Task.FromResult(42), Is.EqualTo(42));
Assert.That("hello", Is.EqualTo("hello"));
await Assert.ThatAsync(() => Task.FromException(new ArgumentNullException)), Throws.ArgumentNullException);
});
}
パフォーマンス面での比較
気になる点としてどちらの方が速いかという点である。
特に、CIパイプラインを構成している場合は費用面でも早く終わってほしい。
テストするプログラム
public static async Task<int> FileSize(string path)
{
byte[] bytes = await File.ReadAllBytesAsync(path);
return bytes.Length;
}
引数で指定されたファイルのサイズを返す簡単なプログラム。
戻り値としてTaskを返す非同期メソッドを含むようにした。
テストクラス
using BenchmarkDotNet.Attributes;
using NUnit.Framework;
[ShortRunJob]
public class Test
{
[Benchmark]
[Test]
public void TestAdd()
{
Assert.That(A.FileSize("C:\\Temp\\test.txt").GetAwaiter().GetResult(), Is.EqualTo(3));
Assert.That(A.FileSize("C:\\Temp\\test2.txt").GetAwaiter().GetResult(), Is.EqualTo(4));
}
[Benchmark]
[Test]
public void TestAddMultiple()
{
Assert.Multiple(() =>
{
Assert.That(A.FileSize("C:\\Temp\\test.txt").GetAwaiter().GetResult(), Is.EqualTo(3));
Assert.That(A.FileSize("C:\\Temp\\test2.txt").GetAwaiter().GetResult(), Is.EqualTo(4));
});
}
[Benchmark]
[Test]
public async Task TestAddMultipleAsync()
{
await Assert.MultipleAsync(async () =>
{
await Task.Run(() => {
Assert.That(A.FileSize("C:\\Temp\\test.txt").GetAwaiter().GetResult(), Is.EqualTo(3));
Assert.That(A.FileSize("C:\\Temp\\test2.txt").GetAwaiter().GetResult(), Is.EqualTo(4));
});
});
}
[Benchmark]
[Test]
public async Task TestAddAsync()
{
Assert.That(await A.FileSize("C:\\Temp\\test.txt"), Is.EqualTo(3));
Assert.That(await A.FileSize("C:\\Temp\\test2.txt"), Is.EqualTo(4));
}
[Benchmark]
[Test]
public async Task TestAddAsyncMultiple()
{
Assert.Multiple(async () =>
{
Assert.That(await A.FileSize("C:\\Temp\\test.txt"), Is.EqualTo(3));
Assert.That(await A.FileSize("C:\\Temp\\test2.txt"), Is.EqualTo(4));
});
}
[Benchmark]
[Test]
public async Task TestAddAsyncMultipleAsync()
{
await Assert.MultipleAsync(async () =>
{
Assert.That(await A.FileSize("C:\\Temp\\test.txt"), Is.EqualTo(3));
Assert.That(await A.FileSize("C:\\Temp\\test2.txt"), Is.EqualTo(4));
});
}
[Benchmark]
[Test]
public async Task TestAddAsync2()
{
await Assert.ThatAsync(() => A.FileSize("C:\\Temp\\test.txt"), Is.EqualTo(3));
await Assert.ThatAsync(() => A.FileSize("C:\\Temp\\test2.txt"), Is.EqualTo(4));
}
[Benchmark]
[Test]
public async Task TestAddAsync2Multiple()
{
await Assert.MultipleAsync(async () =>
{
await Assert.ThatAsync(() => A.FileSize("C:\\Temp\\test.txt"), Is.EqualTo(3));
await Assert.ThatAsync(() => A.FileSize("C:\\Temp\\test2.txt"), Is.EqualTo(4));
});
}
}
以上を、.NET 8で比較した。
結果
Method | Mean | Error | StdDev |
---|---|---|---|
TestAdd | 454.9 us | 51.50 us | 2.82 us |
TestAddMultiple | 458.7 us | 150.44 us | 8.25 us |
TestAddMultipleAsync | 472.0 us | 84.76 us | 4.65 us |
TestAddAsync | 429.5 us | 64.28 us | 3.52 us |
TestAddAsyncMultiple | 440.9 us | 170.92 us | 9.37 us |
TestAddAsyncMultipleAsync | 438.3 us | 39.95 us | 2.19 us |
TestAddAsync2 | 444.3 us | 21.84 us | 1.20 us |
TestAddAsync2Multiple | 445.0 us | 28.82 us | 1.58 us |
あまり、この場合はパフォーマンス差はないみたい。
Discussion