【Swift】TDD（テスト駆動開発）-簡単例で説明-


https://qiita.com/yujioka/items/10f889fccb61b27213bc#stub%E3%82%B9%E3%82%BF%E3%83%96

この記事を見る前に、テストに関しては上記の記事に目を通してください。
こちらの記事の参考例を、テストコードで書いてみることにしました。

今回は一つの関数が、期待した通りの値を返してくれるかどうかを、TDDで実装していく。

実装の仕様内容
-
- 学校のテストの点数の結果によって、評価が変わる
- テストは、0〜１００点の採点である
- 80点以上は「優」
- 60点以上79点以下は「良」
- 30点以上59点以下は「可」
- 29点以下は「不」
を実装していく。

実装していく
-
まず最初に、テストファイルを作成する。
`StudentEvaluationTests`で作成する。
![スクリーンショット 2023-05-06 9.22.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799713/380674ab-c386-6e34-5039-f043d07adedd.png)

次に、`Student`の構造体を作成して、関数を作成する（形だけ）。
最初はどんな値の引数を設定しても、`""` 空文字しか返ってこない返り値を実装。

```swift: Student
struct Student {
    static func evaluationByScore(score: Int) -> String? {
        return ""
    }
}
```

そして、この関数を用いて、
-　引数に値を設定して返って来た値（実際の結果）
-　返って来て欲しい値（期待値）
をテストで実装する。

以下のような実装です。

```swift: StudentEvaluationTests.swift
 func test_Studentの点数に対する評価をテストする() throws {
        XCTAssertEqual(Student.evaluationByScore(score: 110), nil)
        XCTAssertEqual(Student.evaluationByScore(score: 100), "優")
        XCTAssertEqual(Student.evaluationByScore(score: 80), "優")
        XCTAssertEqual(Student.evaluationByScore(score: 79), "良")
        XCTAssertEqual(Student.evaluationByScore(score: 60), "良")
        XCTAssertEqual(Student.evaluationByScore(score: 59), "可")
        XCTAssertEqual(Student.evaluationByScore(score: 30), "可")
        XCTAssertEqual(Student.evaluationByScore(score: 29), "不")
        XCTAssertEqual(Student.evaluationByScore(score: 0), "不")
        XCTAssertEqual(Student.evaluationByScore(score: -1), nil)
    }
```

そして、テストを実行する。（ショートカットキー：`⌘ + U`）
すると、
![スクリーンショット 2023-05-06 14.06.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799713/04fb387a-1863-00be-b669-88e3d812356e.png)
このように、すべてのXCTAssertで、テストが失敗する。
ここから、順番にエラーを生じさせないように、関数を実装していく。

```swift: Student
struct Student {
    static func evaluationByScore(score: Int) -> String? {
        if score > 100 {
            return nil
        }
        return ""
    }
}
```
一番上のAssetを成功できるよう実装。

テストを実行すると、
![スクリーンショット 2023-05-06 14.11.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799713/e4663c05-3978-7390-ae27-a63a31b2c5ca.png)
一番上のAssertが成功している。

次は、２つ目
```swift: Student
struct Student {
    static func evaluationByScore(score: Int) -> String? {
        if score > 100 {
            return nil
        } else if score >= 80 {
            return "優"
        }
        return ""
    }
}
```

テスト実行。

![スクリーンショット 2023-05-06 14.17.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799713/51faae3a-7281-2c77-e5b1-aea15b5bc22d.png)
２つ目も成功。

---
このように繰り返して実装していく。
そこであえて、めんどくさくなったので、雑に実装してみる。
間違い探しだと思って記事をよんでください。
```swift: Student
struct Student {
    static func evaluationByScore(score: Int) -> String? {
        if score > 100 {
            return nil
        } else if score > 80 {
            return "優"
        } else if score > 60 {
            return "良"
        } else if score > 30 {
            return "可"
        } else if score > 0 {
            return "不"
        } else if score < 0 {
            return nil
        }
        return ""
    }
}
```
テストを実行すると、
![スクリーンショット 2023-05-06 14.26.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799713/1e83c663-6f61-36ac-a2d8-b09d182c0046.png)
エラーが起きています。
境界値をどちらに含めるかを曖昧に実装してしまうと、想定通りの実装ができていません。その確認をするためにも、テストコードを書くことは重要です。

上記の実装を修正します。
```swift: Student
struct Student {
    static func evaluationByScore(score: Int) -> String? {
        if score > 100 {
            return nil
        } else if score >= 80 {
            return "優"
        } else if score >= 60 {
            return "良"
        } else if score >= 30 {
            return "可"
        } else if score >= 0 {
            return "不"
        } else {
            return nil
        }
    }
}
```

テストを実行すると、
![スクリーンショット 2023-05-06 14.31.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799713/0c18426b-635a-7c38-396c-b0c47f1d0dc9.png)
成功することができました。

（余談）
今回はif文だけを用いて実装しましたが、Studentの構造体の中でSCOREとして列挙型で評価を定義しておいたほうが、実装は楽だと思います。一つ一つエラーを潰していくイメージを持ってもらうために、if文で順番に実装しました。

---

以上が、簡単なTDDとなります。
このような過程で実装すると、print文で確認しながら行うよりも、①漏れなく実装する＋②テストコードとして、関数が正しく実行されているかを、残すことができます。他にもメリットはありますが、ここでは割愛させていただきます。ただ、テストコードの最初の実装の時点で、期待値を曖昧に設定してしまうと、元も子もないので、注意した方が良いです。


他にも良い方法があれば、コメントいただけると大変うれしいです。
良かったと思ったら、いいねやTwitterのフォローよろしくお願いいたします！

https://sites.google.com/view/muranakar
個人でアプリを作成しているので、良かったら覗いてみてください！