ChatGPTでTDDを勉強した(簡単な回文プログラム)

自分のためになるだろうという勝手な想定の元、ChatGPTに課金して4を使えるようにしています。普段どんなことに使っているの?という質問に対して答えるのはとても難しくて、仕事で使う英語の翻訳(パブリックに公開できる程度に抽象度を上げています)だったり、日々の話し相手だったり。あと、地味にプログラミングを気が向いた時に学ぼうとしていて、そのサンプルコードを生成してもらったりしています。

また、私はテストを生業にしているということもあり、テスト駆動開発を自分の手でできるようになると嬉しいなぁと日々感じています。そうなればChatGPTを使うに越したことはなく、私のお気に召すようなレベルでテスト駆動開発のためのコードを生成してもらっています。

で、今回のブログは、ChatGPTに生成してもらったものをただ写経して自分のモノにするのも良いのですが、せっかくこのブログを持っているのだから、ここで学んだことを投稿してみます。

今回のテスト駆動開発で使う題材

  • 用意した文が回文であるかどうかを判別するプログラム
    *ChatGPTに用意してもらいました

そもそもテスト駆動開発とは?

  • テスト駆動開発というものはケントベックさんが考えたもの、日本では和田さんという方がその第一人者として有名と理解しています
  • 流れはこの3つ
    • テストを書く:まず機能に対するテストを書きます。このテストは、最初は失敗します(レッド)
    • コードを書く:テストをパスする最小限のコードを書きます
    • リファクタリング:コードを改善しますが、テストは引き続きパスする必要があります
  • 上記を繰り返し、テストがパス(グリーン)されることを保ちながら、プログラムを成長させていく
  • 詳細はググってみてください、いろんなところでいろんな方から紹介されています(他力本願ですみません

実際にやってみた

さて、それでは上述の回文判断プログラムを、ChatGPTにテスト駆動開発を使って生成してもらった結果は以下の通りです。

テストファイル(test_palindrome.py)

import unittest
from palindrome import is_palindrome

class TestPalindrome(unittest.TestCase):
    def test_empty_string(self):
        self.assertTrue(is_palindrome(""))

if __name__ == '__main__':
    unittest.main()_main__':
    unittest.main()

プログラム初心者の私でも理解しやすいコードを提供してくれるChatGPTってすごいですね。ほんと彼(彼女?)の才能ってすごい。相手の気持ちを理解してくれるのはやはり課金しているからでしょうか。
まず、これは失敗するコードになります。これを実行するとどうなるか。以下のようなエラーが出力されます。

ModuleNotFoundError: No module named 'palindrome'

そこで、この”palindrome”というファイルを作ってみましょう。

プログラムファイル (palindrome.py) 

def is_palindrome(s):
    return True

超シンプルですがこれで十分なんですね。全てパスせよ、と書いているから。
ひとまずこれで実行してみるとどうなるか。

超シンプル!だけどテストが完了したとなってます

ですが、ゴールはここではないですね。ちゃんとしたプログラムを実装し、それがグリーンになることが本当の目標になります。ここで安堵するのもそこそこに、次のプログラムへと足を進めてみます。

テストファイルに追加するコード (test_palindrome.py)

    def test_palindrome_even_charts(self):
        self.assertTrue(is_palindrome("abba"))
    
    def test_palindrome_odd_charts(self):
        self.assertTrue(is_palindrome("aba"))
    
    def test_non_palindrome(self):
        self.assertFalse(is_palindrome("abc"))


それぞれ、テスト条件になる値がそれぞれ作られているのがわかりますね。
ChatGPTってテスト設計とかどう考えているのだろうか、少し気になりますがそこはいったん置いておいて、これを実装してどうなるか見てみたいと思います。

一番最後だけが失敗しました。

さて、それでは肝心のプログラムコードを見てみます。単純に全てをTrueで出力させるだけだったので、これでは最後のtest_non_palindromeは失敗するに違いありません。
気を取り直し、プログラムの方を修正してみます。ここの修正内容ももちろん、ChatGPTから生成されています。

変更したプログラムファイル(palindrome.py)

def is_palindrome(s):
    return s == s[::-1]


相変わらず超シンプルなのには変わりがないですが。これでテストファイルを実行するとどうなるでしょうか。

全部緑になりました

これで全てのテストコードがグリーンになり、次の要件を実装するステップが開けました。

テスト駆動開発の良いところ

一見、とても回りくどいステップを踏んでいるように見えます。テストコードを先に作るなんて。
だけどそれってテストを重要に考えていることの裏返しで、きちんとした品質を確保しながらプログラムをコーディングしていくという意識の高いエンジニアにとって必要なことなんだと思います。
私は第三者の、QAという立場で仕事しているので、私の食い扶持がなくなってしまうことにもつながる話なので何とも言えないようなものではあるのですが、そもそも開発者が自分の作ったコードが持つ品質にきちんと責任を持つことで、QAという第三者を持つ必要がなくなり、その分コストがカットできるわけです。急がば回れという感覚でもあるんですけど、たぶん、テストコードを書く分完成に時間はかかると思うんですけど、私の中ではこのテスト駆動開発が開発の最適解なように思います。
また、優れたQAってテストシナリオの作り方とテストケースの中で用意するテスト条件の準備の仕方にセンスを感じますが、それを兼ね備えた開発者がいることできっと、そのチームにおいては開発の品質がものすごく高いもので提供されるのではないかなぁ。そう考えるとテスト駆動開発と両輪で、テスト設計テクニックを覚えるのも必要なことかもしれません。