テストツールを作るならNUnitConsoleのほうが


# 最初にまとめ

こんな内容の記事です。

 * ボタンかコマンドがたくさん並んだ一品もののテストアプリを、毎回一から作ってる？
 * それなら、UI部分はNUnitConsoleに任せて、ロジックだけに集中しよう！ 
 * その使い方を紹介

# 概要

DLLのようなロジックだけを開発する場合、テスト用にそれを色々なパラメータで呼び出すテストアプリを作ることが有ると思います。ボタンとコンボボックスとテキストボックスが大量に並んだテストアプリ、見たことがある人は多いんじゃないでしょうか。

こんな感じの画面

![GuiSample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616143/7b2e6c14-b99d-af0f-d7e4-0931d69b3282.png)

あるいはこんな感じでコマンドを打つツールです。

![commandSample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616143/a6570ce8-66d1-9b28-1a68-6e61be70d2f0.png)



そうしたテストツールを書くのにも、単体テストコードでお馴染みのNUnitを使うという手があります。NUnitというと開発環境の上で、VisualStudio等の開発IDEから実行するイメージが強いと思いますが・・・
実は、テスト環境で実行することもできます。NUnitのDLLをコマンドプロンプトから実行できるNUnitConsoleを使います。

こんな構成です。

```plantuml
@startuml

component "コマンドプロンプト" as cmd {
    component "NUnitConsole.exe" as console
}

component "自分でNUnitで作ったDLL" as nunit {
    component "テストコード" as test
}

actor "ユーザー" as user

user --> console : コマンドで実行
console --> test : 処理実行


@enduml
```

つまり、exeとしてのインターフェース部分（コマンドの解析処理など）はNUnitConsoleにお任せして、いきなりDLLを呼び出せるということです。

これを使えばテストアプリを作るときに、さっそくロジックから書けます。テストツール作成にありがちな、一品物のUI部分（CLI含む）を毎度毎度作り込むような工数の無駄が、省けるというわけです。

さらに普段から単体テストコードを書いているようなプロジェクトであれば、単体テストのコードをそのまま生かすこともできて、より効率が良くなります。
単体テスト実行の時はスタブを与え、テストツールとして実行するときは本物のインスタンスを与えれば良いわけです。

つまりこういうことです。

```plantuml
@startuml

class "テスト対象クラス" as target

interface "実処理のI/F" as if
class "実処理" as inst
class "スタブ" as stub

target o-- if
if <|-- inst : テストツールとして使う場合
if <|-- stub : UnitTest自動実行の場合

@enduml
```




# 使ってみる

メリットを語ったところで、実際の使い方を紹介していきます。

## テスト環境に入れる

NUnitConsoleをここからダウンロードして、テスト環境に持ち込みます。

https://github.com/nunit/nunit-console/releases/latest

zipとmsi（インストーラ）があります。msiの方がパスも通してくれるなど楽そうですが、バージョン3.17.0を試したら.NET 8版が含まれていなかったりしたので・・・zipの方を解凍してカレントに気をつけて実行する方が良いかもしれません。以下はzip前提で書きます。

## 準備

まず最初に、どのバージョンの.NETで実行するかを決めます。バージョンごとにフォルダが分かれていますが、自分が作成したNUnitのDLLに合わせたものを選んでください。今回の例では.NET 8で作成したので、「bin\net8.0\nunit3-console.exe」を使用します。そのため、「bin\net8.0\」のフォルダをコマンドプロンプトのカレントにします。DLLロードの都合で同じフォルダに有った方が楽なので、テスト対象のDLLも同じフォルダへ置きます。

## 指定したメソッドを実行する

NUnitで作成してビルドしたDLL（ここではNUnit1.dll）を用意します。最初の例では、その中で「Test1」というメソッドを実行してみます。こんなコマンドになります。

`nunit3-console.exe NUnit1.dll --where="method == Test1"`

割と直観的に使えそうな感じではないでしょうか。exeの1つ目のオプションにテスト対象DLLを渡し、「--where」オプションで、実行したいメソッドの条件を指定します。

ここでは、メソッドTest1を、こんな感じでメッセージだけ出力する実装にしています。
```csharp
[Test]
public void Test1()
{
    Console.WriteLine("Test1 Run");
}
```

すると、こんな感じで実行されます。「Test1 Run」の部分が、テストコード内で出力したメッセージです。
![スクリーンショット 2024-02-15 203118.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616143/14b4db56-dbf1-b2a5-25e4-f64c58ac196c.png)

ここでは、「メソッド名がTest1と完全一致する」という条件にしました。--whereには、正規表現での指定や、名前のみならずAutherでのフィルタなど色々なオプションがあるので、やりたいことはだいたいできると思います。詳しくはこちらを。
https://docs.nunit.org/articles/nunit/running-tests/Test-Selection-Language.html

## パラメータを変えて実行する

テストツールとして使うには、パラメータを与えて実行するという使い方も必要です。テストコードの実装側で、TestContext.Parametersでパラメータを受け取るように実装しておけば、コマンドでパラメータを与えることができます。

テストコード側の実装はこのようになります。パラメータを指定されていない場合はnullが返るので、その場合は"default"と言うパラメータで動作するように実装しています。

```csharp
[Test]
public void Func2()
{
    var param1 = TestContext.Parameters["param1"] ?? "default";
    Console.WriteLine($"Func2 Param {param1}");
}
```

このコードを次のコマンドで実行してみます。パラメータ「param1」に値「value1」を与えています。

`nunit3-console.exe NUnit1.dll --where="method == Func2" --testparam:param1=value1`

すると、このようになります。「Func2 Param value1」と出ているので、"default"ではないパラメータをコマンドから与えられたことが分かります。

![スクリーンショット 2024-02-24 150009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616143/bcdc88ee-9119-e4a7-2f93-2410a6400661.png)

# まとめ

NUnitの使い方さえ理解してしまえば、NUnitConsoleを使った方が、いちいちテストのためだけのアプリを1から作るより楽ではないでしょうか？NUnitは初めてなので学習が必要だという場合でも、UnitTestのコードを気軽に書けるように慣れておくことは、無駄にはならないと思います。次にテストアプリを書こうと思った時には、ぜひ使ってみてください。