「かごんま.NET 勉強会 #5 テストツール」に参加した

かごんま.NET 勉強会 #5 テストツール
---

# 1. TL;DR

- かごんま.NET 勉強会 #5 テストツール

    2020/01/29(水)

    https://kagoshima-dotnet.connpass.com/event/162253/

- 内容
  - [NUnit の使い方](#2-nunit-の使い方)
  - [テストコードの書き方](#3-テストコードの書き方)
  - [モックやスタブを使った単体テスト](#4-モックやスタブを使った単体テスト)

---

# 2. NUnit の使い方

演者：makoto kozono 様

## 2.1. 内容

.NETのユニットテストツール「NUnit」について基本的な説明を行っていただきました。

## 2.2. なぜNUnit？

なぜNUnitを選択したかというと、やはりユーザー数が多いため、ということでした。確かにユーザー数が多いと困ったときのトラブルシューティング情報も多いですし、日本語のドキュメントが存在する確率も高くなります。

## 2.3. 他にはどんなツールがある？

.NETでは、xUnit.net、MSTest、NUnitの3種類がある

## 2.4. NUnitのデモ

ここから実際に使い方をデモいただきました。

環境は以下でした。

- VS2019 Communitiy
- Test Generator Extension
- NUnit

### 2.4.1. Test Generator Extensionについて

GUIからメソッドに対する単体テストを作成することができるが、Test Generator Extensionをいれることで対象として、NUnitのテストフレームワークが追加される

### 2.4.2. 単体テストの作成

単体テストはGUIから作成できる。もちろんGUIを使わないという方法も可能であり、なれたらGUIから作らないことも多い。今回はGUIからやってみる。

GUIから単体テストを作成すると、必要なライブラリの追加、参照なども自動で行われる。

ほかのユニットテストツールもだが、NUnitの特徴としては、テストメソッドに属性をつけていくことになる。例えば、TestFixture、Test（実際のテストメソッド）、TetCase（同一テストメソッドに大したパラメーターのみを変えたい）、Setup（テスト前に実行される処理）など

今はテストに属性を追加することでテストメソッドとして認識されるが、昔はプロジェクトの名称、メソッドの名称で区別されていた。なのでプロジェクト名称は「Tests」で終了し、メソッド名は「Test]で行うことが多い。

例外により、成功・失敗を判断したい場合も、シンプルな形で書ける（`Assert.That`）

## 2.5. 制約モデルについて

制約モデルとは、`Asset.That`を使用する書き方で、そのあとに結果、期待値と続き、期待値の制約`Is.EqualTo(xx)`、`Is.GreaterThan(xx)`を記載する。

昔の書き方である`Assert.AreEauals`と比較すると、色々な利点がある。具体的には、パラメーターの渡し方の順番がどちらだったのかわかりにくい（結果→期待値なのか、期待値→結果なのか）という点を改善できる、期待値（同一値を判定したいのか、大小比較を判定したいのか）を言葉に近い形で記述することができる、などがあげられる。

つまり、間違いにくいコードを書くことができるので、テストコードを効率的に記載できる。

参考：https://qiita.com/tokishirazu/items/139e5b51936a1f1e9af0

## 2.6. NUnit 5ではどのような機能が追加されたのか？

メソッドチェーンとなったのでわかりやすくなった。

テストツールというのは破壊的な変更というのは行われず、互換性が大事にされている。ウエブ関連のツールのように破壊的な変更が行われるのであれば、テストをコードで書くということ自体が成り立たない。

## 2.7. よく使う制約は？

- Is
- Has
- Does
- Throws

---

# 3. テストコードの書き方

演者：Masayuki Kuratsubo さん

## 3.1. NUnitのドキュメント（公式）

https://docs.nunit.org/

## 3.2. テストのプロセス

- テストメソッドを呼び出す準備
- テスト対象の実行
- メソッドの結果を検証
- 後片付け

## 3.3. 例えば

### 3.3.1. テストメソッドを呼び出す準備

ファイル準備

### 3.3.2. テスト対象の実行

メソッド実行

### 3.3.3. メソッドの結果を検証

Assert検証

### 3.3.4. 後片付け

テストで作成したファイルを後片付け

## 3.4. サンプルの問題点

- すべて読む
- 1行だけ読む

というテストを書いたがコードのかぶりが多い。

## 3.5. どうする

属性を利用できる

### 3.5.1. Setup, SetupFixture

ファイルの準備とクラスの初期化

| 属性名       | 内容                                                                           |
| :----------- | :----------------------------------------------------------------------------- |
| Setup        | TestCaseごとの場合は、それぞれで実行され、同時実行されることを想定して作ること |
| SetupFixture | クラスで1回                                                                    |

### 3.5.2. TearDown, TearDownFixture

テストの後片付け

| 属性名          | 内容                                                                           |
| :-------------- | :----------------------------------------------------------------------------- |
| TearDown        | TestCaseごとの場合は、それぞれで実行され、同時実行されることを想定して作ること |
| TearDownFixture | クラスで1回                                                                    |

## 3.6. 属性

| 属性名      | 内容                                 |
| :---------- | :----------------------------------- |
| TestFixture |                                      |
| Timeout     | タイムアウトするとき                 |
| Test        |                                      |
| TestCase    |                                      |
| Ignore      | 一時的だが使わないほうが良い         |
| TestCase    |                                      |
| Order       | テストの順番に意味があるときにつける |
| Assert      |                                      |

## 3.7. Assert

| メソッド名 | 内容                                     |
| :--------- | :--------------------------------------- |
| Is         | 単体。Is.EmptyとIs.Nullは別。のはず      |
| Has        | コレクション                             |
| Does       | 文字列の検証。含むなど。正規表現も使える |
| Collection |                                          |
| Throws     |                                          |

### 3.7.1. コレクション

Is.AllNotNull, ALl.LessThan, ALl.LessThanEqual

### 3.7.2. ディレクトリ

Does.Exist, Is.Empty

### 3.7.3. 例外

Throws 例外、例外の型、メッセージ

#### 3.7.3.1. 例外の合成

Assert.That

Assert.Multiple

## 3.8. TestCase, TestCaseSource

| メソッド名     | 内容                                                                                                   |
| :------------- | :----------------------------------------------------------------------------------------------------- |
| TestCase       | 複数のテストを走らせることができる。                                                                   |
| TestCaseSource | クラスをテストデータとして使用することができる。テストデータのクラス内でファイルやDB処理をさせればよい |


## 3.9. 重複部分をまとめるには

- 継承を利用する
  - 基本Classと共通のSetUpとTearDownをまとめる
  - 派生ClassとそれぞれのSetUpとTearDownをまとめる
  - メソッドの属性のみで判断される

## 3.10. IzとIs

VB.NETではIsの代わりに、Iz。理由はVB.NETではIsが予約語のため。

https://docs.microsoft.com/en-us/dotnet/api/nunit.framework.iz?view=xamarin-ios-sdk-12

---

# 4. モックやスタブを使った単体テスト

演者：政倉 智 様

[プレゼンテーション資料](https://docs.google.com/presentation/d/14FOzR0zHzDdcKCeGs2Q4GIMAe00IKJp-yaejXn8duI0/edit#slide=id.p)

詳細は上記プレゼンテーション資料をご参照ください。
口頭でご説明いただいたことを中心に記載します。

## 4.1. MSTestがNUnitにくらべて機能がないところ

- TestCaseがない
- 例外の扱いが面倒
- MSTestは機能追加は行わずメンテのみ

## 4.2. テストフレームワークは寿命が長くないといけない

バージョンアップしても、互換性は保たれる。バージョンアップで動かなくなるならテストフレームワークとして使いづらいので、

## 4.3. テストは簡単に壊れる

コピペでいいか？いやちゃんと考えて作ったほうがいい。
ある意味プロダクションよりちゃんと作ったほうがいい。

### 4.3.1. 例

- 設定ファイルで有効桁数を設定できるように
- 設定ファイルを切り替えられるようにすればよいか？
  - ファイルを2つ用意して上書きする？
    - 順序に依存しやすい
      - テストが信用できなくなって書かなくなる
      - テストの順番は保証されていない。
    - 並列でテストできない
      - ファイルのコピーを工夫する？テストの順番

### 4.3.2. 外部コンポーネントに依存するクラスはテストしにくい

- Configurationを読むようになった段階でテストしにくくなる

## 4.4. 依存を断ち切る

### 4.4.1. スタブ

- テスト用のデータ
  - テスト用のコンストラクターを用意する
    - テスト用に実装を変えていいのか　→　よい！

## 4.5. DB

並列でテストしにくいという問題がある。

### 4.5.1. やり方

- データベースにアクセスするクラスとビジネスロジックを分ける
  - データベースにアクセスするクラスを切り替えられるようにして渡す
  - データの状態に依存する
  - CustomerDataSourceの代わりにCustomerRepositoryStub

## 4.6. テスト駆動開発

未完成でもテストができるようになる。
テーブル設計が未完成でもテストできるようになる。

## 4.7. Moq

- .NET 向けの近代的なモックライブラリ
  - クラスの自動生成
- スタブをMoqで作るとわかりにくくなる

### 4.7.1. スタブとモックとは

- モックはスタブの一種派とモックとスタブは違う派閥がある

- モックは、オブジェクトに渡すところも検査する

   ```
   mock.Verfy()
   ```

-  Moqは、メソッドが何回呼び出されたかを検証できる

### 4.7.2. 注意

- モックは専用のライブラリを使ったほうが楽
- ホワイトボックステストになりやすい

### 4.7.3. 公式

https://qiita.com/usamik26/items/42959d8b95397d3a8ffb
https://github.com/moq/moq4

## 4.8. ドメインオブジェクト

### 4.8.1. よくある三層プロジェクト

- アプリケーション層のテストをするとインフラストラクチャ層のテストができない

### 4.8.2. どうする

- ドメインオブジェクトを作って、ドメインオブジェクトにビジネスロジックを書く
- ドメインオブジェクトのテストだけをすればよくなるので、モックやスタブはいらない

## 4.9. まとめ

- テストメソッドが1000行となることもあるので、テストの維持が難しくなる
- テストメソッドを適当に書きすぎると、テストコードの変更が大きくなり、仕様変更にコストが大きくなるので、少しずつやっていくのが良い。データベースはテスト時には使わないなど

## 4.10. NUnitとxUnit.Netの違い

- xUnitはクラスに何もつけなくてもよい
- 属性の名称が異なる
- MicrosoftはxUnit.Netを押しているのでは
- NUnitのSetup, TearDown→xUnit.Netのコンストラクター, デストラクタ

### 4.10.1. xUnit.Netの疑問

- 失敗したときにデストラクタが動かないのではないか。

## 4.11. Power Assert

- JavaScript用のライブラリ
    https://qiita.com/billthelizard/items/b5b74a75ad716e75687c

   > 和田卓人さんが開発した javascript のアサーションのライブラリ1です。
   > 
   > 普通のアサーションと比べて、簡単な書き方でより多くの情報を提示してくれます。
   > 
   > しかも、既存のテストコードに node.js 標準の assert を使っている場合は、 require の部分を差し替えるだけで移行することができます。