👏

TUnit を使おう!

2024/09/16に公開

TUnit を使おう!

TUnit は最近プレリリースされた .NET 用のテストフレームワークです。

GitHub では次のように説明されています。

A modern, flexible and fast testing framework for .NET 8 and up. With Native AOT and Trimmed Single File application support included!

何がいいの?

TUnit の作者は NUnitxUnit.net に不満があるようです。(私もですが...) 公式ドキュメントの Framework Differencesでそれらとの違いについて説明しています。

その中で自分が気になるものを紹介します。

NUnit

NUnit はテストクラスのインスタンスをテストケースで共有しています。テストの完了をより早くするためにテストケースを並列で動かすのですが、インスタンス変数が勝手に書き換わってテストが超不安定になってよく戸惑ってました。(自分が xUnit.net に乗り換えた理由がこれです)

TUnit はテストケースごとにテストクラスのインスタンスを作成します。並列テストもデフォルトで有効です。

ただし、NUnit も今では FixtureLifeCycle で挙動を変えられるので、大きな問題ではありません。でも、忘れると混乱するので、デフォルト共有しない方がうれしいのは間違いないです。

xUnit.net

xUnit.net はテストアセンブリ毎の初期化や後始末はそれほど簡単ではありません。Collection Fixtures という機能を利用すれば、できますがちょっとやり方が面倒です。

詳しい方法は省略しますが、初期化や後始末をするコレクションフィクスチャクラスを別途定義して、テストクラスをそれぞれ同じコレクションに所属させます。

[Collection(nameof(MyCollection))]
public class UnitTest1
{
    // ...
}

[Collection(nameof(MyCollection))]
public class UnitTest2
{
    // ...
}

xUnit.net v3 では Assembly Fixtures が導入されるので、将来は改善されるでしょう。

アサーション

TUnit の作者はアサーションについても言及していますが、私自身は PowerAssert.Net を利用しているのであまり気にしてません。

xUnit.net (個人的な意見)

xUnit.net は NUnit より新しく、テストケースごとにインスタンスを別々に作成します。このため、テストの並列実行に強いと認識していました。

しかし、テストの並列化の最小単位がコレクションとなります。コレクションはデフォルトではクラスで、クラス内に大量に作成したパラメーターテストを並列実行できません。

しかも、フィクスチャを複数のテストクラスで共有するためにコレクションフィクスチャを導入すると、さらに並列実行されなくなります。例えば、ASP.NET Core のアプリケーションテストを用いる場合、テスト用のアプリケーションインスタンスをコレクションで共有するのですが、そうなるとすべてのテストが並列実行されなくなります。残念なことに、テストの並列実行は NUnit の方がまだ使いやすいです。

もう一つ xUnit.net には困ったことがあります。xUnit.net は InlineData 属性などでパラメーターテストができますが、これが使えるのはメソッドのみでクラスには指定できません。クラス単位でパラメーターテストをしたい場合でも、テストケースごとにそれぞれ指定しなければなりません。

これらの問題で、私は xUnit.net から NUnit に戻っています。

TUnit をはじめる

TUnit はこれらの問題がないのでとてもハッピーです。テストケースの並列実行はデフォルトですし、クラス単位のパラメーターテストもできます。テストの順序や依存関係などの自分が今まで知らなかった面白そうなものや、ソースジェネレーターや AOT にも対応しているようです。

はじめるのは簡単です。公式ドキュメントの Installing TUnit の通りです。

$ dotnet new console --name YourTestProjectNameHere
$ cd YourTestProjectNameHere
$ dotnet add package TUnit --prerelease

テストクラスは次のようになります。標準のアサーションは非同期でなくても async で書くようです。

public class FooTest
{

    [Test]
    public async Task TestAdd()
    {
        var result = 1 + 2;

        await Assert.That(result).IsEqualTo(2);
    }
}

PowerAssert を利用する場合は public void TestAdd() でも問題ありませんでした。

実行はほかのテストフレームワークと同じで dotnet test です。

JetBrains Rider からテストする

JetBrains Rider は有償の IDE ですが、Visual Studio と異なりマルチプラットフォームだったり、軽かったり、使いやすかったりで重宝しています。自分としては Rider からサクサクテストできるかが重要です。

Rider のドキュメントの Unit testing を読むと、正式リリースもまだな TUnit は対応していません。しかし、Microsoft.Testing.Platform に対応しているテストフレームワークは利用できるようです。TUnit は Microsoft.Testing.Platform 対応なので動きます。

設定のビルド、... -> ユニットテスト -> VSTestEnable Testing Platform Support を有効にするだけです。

とりあえず Rider からテストを実行してテスト結果を見ることができましたが、サポートされている NUnit や xUnit.net と同じような使いがってとはいきませんでした。

  • ソースコードのテストケースの左側側にテストボタンが出てこない
  • テスト結果からソースコードに飛べない
  • 再ビルドしないとテストエクスプーラーのテストケースが修正されない

残念...

最後に

自分が NUnit や xUnit.net に持っている不満を総じて解決しているので、TUnit にはとても期待しています。Rider からさくっと使えるようになったら本格的に導入しようかなと思います。

唯一の欠点は .NET 8 専用だということです。世の中まだ .NET Framework も残ってるんですね...

Discussion