ユニットテストにも可読性を持たせる (Four Phase Test)

#はじめに
ユニットテストを書いていると、
プロダクトコード同様、可読性が悪くなってきますよね。

ユニットテストの「Four Phase Test」という考え方について、
はじめて知ったので簡単にまとめます。

「Four Phase Test」とは、下記のような4つの手順に分けて、
実施する方法です。

|No.| フェーズ | 説明 |
|---|---|---|
|1.|Setup | 前処理 |
|2.|Exercise | 実行 |
|3.|Verify | 検証 |
|4.|TearDown | 後処理 |

# 可読性が悪くなる原因
テスト毎の前提条件や、後処理など、
検証以外のテストコードが増えてきたときに、
どこが実行部分で、どこが検証部分か分かりづらくなりがちです。

# 解決策の方針
そこで、「Four Phase Test」の手順に則って、
テストコードを実装してみる。
（他にもあれば、ご教授願います。）

ユニットテスト全体で共通のSetupとTearDownは、意識していましたが、
ExerciseとVerifyは、意識できていませんでした。

# リファクタリング対象のテストコード
コード量も長くなり、可読性が落ちています。

```swift:WarikanModelTests.swift
import XCTest
@testable import Warikan

class WarikanModelTests: XCTestCase {

    let usecase = WarikanUsecase()
    let delegete = SpyWarikanDelegate()

    override func setUp() {
        super.setUp()
        usecase.delegate = delegete
    }
    
    override func tearDown() {
        super.tearDown()
        usecase.delegate = nil
    }
       
    func test10000div3() {
        
        let exp = expectation(description: "10000円を3人で割り勘したときのテスト")
        delegete.asyncExpectation = exp
        
        usecase.calc(totalAmountStr: "10000", numberOfPeopleStr: "3")
        
        waitForExpectations(timeout: 1) { error in
            if let error = error {
                XCTFail("waitForExpectationsエラー: \(error)")
            }
            
            switch self.delegete.result! {
            case .success(let bugetStr):
                XCTAssertEqual(bugetStr, "1人辺りの支払い額は、3,400円です。")
                
            case .error(_) :
                XCTFail("テスト失敗")
            }
        }
    }
}
```

## リファクタリング①
コメントで、4つのフェーズに分けます。
一旦、グルーピングは出来ました。
但し、別の前提条件のテストをするときなど、冗長になることもあります。

```swift:WarikanModelTests.swift

/* test10000div3は、割り切れないときのテストを実行します。
 * Check: 10000 / 3 = 3400.
 */
    func test10000div3() {
        
        // 1. Setup
        let exp = expectation(description: "10000円を3人で割り勘したときのテスト")
        delegete.asyncExpectation = exp

        // 2. Exercise
        usecase.calc(totalAmountStr: "10000", numberOfPeopleStr: "3")
                
        // 3. Verify
        waitForExpectations(timeout: 1) { error in
            if let error = error {
                XCTFail("waitForExpectationsエラー: \(error)")
            }
            
            switch self.delegete.result! {
            case .success(let bugetStr):
                XCTAssertEqual(bugetStr, "1人辺りの支払い額は、3,400円です。")
                
            case .error(_) :
                XCTFail("テスト失敗")
            }
        }
        
        //4. TearDown
    }
```

## リファクタリング②
ヘルパーメソッドで、4つのフェーズに分けます。
ヘルパーメソッドの切り出すと、
リファクタリング①で上げた冗長な記載はなくなりました。
合わせて可読性も上がりましたね。

```swift:WarikanModelTests.swift
/* test10000div3は、割り切れないときのテストを実行します。
 * Check: 10000 / 3 = 3400.
 */
    func test10000div3() {
        
        // 1. Setup
        whenWarikan(description: "10000円を3人で割り勘したときのテスト")

        // 2. Exercise
        usecase.calc(totalAmountStr: "10000", numberOfPeopleStr: "3")
        
        // 3. Verify
        verifyWarikanResult(bugetStr: "1人辺りの支払い額は、3,400円です。")
        
        //4. TearDown
    }
    
    // 1. Setup
    private func whenWarikan(description: String){
        delegete.asyncExpectation = expectation(description: description)
    }
    
    // 2. Exercise
    private func exerciseWarikan(totalAmountStr: String, numberOfPeopleStr: String) {
        usecase.calc(totalAmountStr: totalAmountStr, numberOfPeopleStr: numberOfPeopleStr)
    }
    
    // 3. Verify
    private func verifyWarikanResult(bugetStr: String) {
     
        waitForExpectations(timeout: 1) { error in
            if let error = error {
                XCTFail("waitForExpectationsエラー: \(error)")
            }
            
            switch self.delegete.result! {
            case .success(let bugetStr):
                XCTAssertEqual(bugetStr, bugetStr)
                
            case .error(_) :
                XCTFail("テスト失敗")
            }
        }
    }
```

# まとめ
ユニットテストにも可読性が求められますね。
一つの方針として、「Four Phase Test」も推進していきたいです。

## その他の語録

|用語 |　説明 |
|---|---|
|Test | テストケース |
|Suite | Testをまとめたもの |
|SUT | 「System Under Test」の略で、テスト対象のこと|
|Fixture | 個別の期待結果を生成するためのまとまり。「Setup」を何らかの形で特化させたものになる。|