【unittest】Pythonでじゃんけんプログラムのテストをやってみよう

プログラミング
スポンサーリンク

スポンサーリンク

はじめに

どーも、学生エンジニアのゆうき(@engineerblog_Yu)です。

今回はソフトウェア開発に興味がある初心者の方向けに、テストを解説していきます。

ソフトウェア開発においてテストをすることは避けては通れない道となっています。

今回は最も単純な例を使ってテストを行なっていこうと思います。

まずはソフトウェア開発におけるテストとは何か?

何でテストが必要なの?ということについて解説していこうと思います。

テストの必要性

ソフトウェア開発をする際には膨大なコードを記述します。

もちろんコーディングは人間がするのでミスがつきものです。

もしミスが生まれたら膨大なコードの中から探すのはとても大変です。

みなさんは小学生の時、新聞などで「の」の字探しはやりませんでしたか?

コーディングミスの発見は「の」の字探しの100倍大変です。(笑)

そんなコーディングミス発見の手間を減らしてくれるのがテストとなっています。

テストをすることでコードのどこが間違っているのかを素早く見つけることができます。

というわけで実際に単純な例でテストを行なっていこうと思います。

単純なコードのテスト(helloworld.py)

まずはhelloworld.pyというPythonファイルを作成していきます。

中身はhelloworldという’Hello World’を出力する関数のみです。

# Hello Worldという文字列を返す関数
def helloworld():
    return 'Hello World'

今回はhelloworld関数がちゃんとHello Worldを返してくれますか?ということについてテストを行なっていこうと思います。

test_helloworld.py

それではメインとなるtestを行っていきます。

helloworldと同じディレクトリにtest_helloworldを作成していきます。

テストを行うPythonファイルの名前の始まりはtestをつけることに気をつけましょう。

# テストを行うためのモジュールのインポート
import unittest

# helloworld.pyの関数を使うためのインポート
import helloworld


class TestHelloWorld(unittest.TestCase):

    #helloworldをテストする関数
    def test_helloworld(self):

        # helloworld関数を呼び出してmessageに格納する
        message = helloworld.helloworld()

        # messageと'Hello World'が同じであるか判定する
        self.assertEqual(message,'Hello World')


if __name__ == '__main__':

    unittest.main(verbosity=2)

最も大切なところは以下の部分です。

# messageと'Hello World'が同じであるか判定する
self.assertEqual(message,'Hello World')

messageはhelloworld関数の結果が入ります。

そして二つ目の引数は返ってきて来て欲しい値を入れます。

今回の場合はHello Worldです。

messageの中に格納されている値とHello Worldが同じ場合にテストが成功するということになります。

それでは実行してみましょう。

test_helloworld.pyを実行してみる

test_helloworldを実行してみるとこのような出力が出ます。

test_helloworld (__main__.TestHelloWorld) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

OKと表示されて、ちゃんと予想通りの動作がhelloworldで行われていることがわかります。

もしテストがうまくいかなかったら?

test_helloworld関数の’Hello World’を’Hello’に変えて、あえてテストを失敗させてみます。

# messageと'Hello World'が同じであるか判定する
        self.assertEqual(message,'Hello')

するとこのような出力になります。

test_helloworld (__main__.TestHelloWorld) ... FAIL

======================================================================
FAIL: test_helloworld (__main__.TestHelloWorld)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_helloworld.py", line 10, in test_helloworld
    self.assertEqual(message,'Hello')
AssertionError: 'Hello World' != 'Hello'
- Hello World
+ Hello


----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

Hello WorldとHelloは違うよ!って怒られているのが分かりますね。

次は実践編ということで以前私が作成したじゃんけんプログラムについてもテストを行なっていこうと思います。

じゃんけんプログラムのテスト(jyanken.py)

以前私が作ったじゃんけんを行うプログラムについてテストをしていきたいと思います。

以下のプログラムではグーを1、チョキを2、パーを3としています。

また第一引数を自分の出した手、第二引数を相手が出した手としています。

# グー:1、チョキ:2、パー:3とする

def jyanken(a,b):
    if a == b:
        return 'あいこです。'
    elif a == 1 and b == 2:
        return '相手はチョキを出しました。あなたの勝ちです。'
    elif a == 1 and b == 3:
        return '相手はパーを出しました。あなたの負けです。'
    elif a == 2 and b == 1:
        return '相手はグーを出しました。あなたの負けです。'
    elif a == 2 and b == 3:
        return '相手はパーを出しました。あなたの勝ちです。'
    elif a == 3 and b == 1:
        return '相手はグーを出しました。あなたの勝ちです。'
    elif a == 3 and b == 2:
        return '相手はチョキを出しました。あなたの負けです。'
    else:
        return '1~3の数字を入力してください。'

main.py

main.pyでjyanken.pyを実行してみます。

まずはinputを用いてターミナルから1から3までの数を入力できるようにします。

次にrandom.randintというメソッドを使ってランダムな1から3までの数をbに格納しています。

import random
import jyanken

if __name__ == '__main__':
    a = int(input('(グー:1,チョキ:2,パー:3)あなたが出す手は?:'))
    b = random.randint(1, 3)
    #相手の出す手をランダムに発生
    result = jyanken.jyanken(a,b)
    print(result)

実行結果はこうなりました。

(グー:1,チョキ:2,パー:3)あなたが出す手は?:1
相手はパーを出しました。あなたの負けです。

惜しくも負けてしまいました。(笑)

これらのプログラムがちゃんと正しく出力してくれるかということについてテストしていこうと思います。

test_jyanken.py

それではテストの方を行なっていきます。

やっていることは同じですが少しコードが複雑になっています。

import unittest
import jyanken

class TestJyanken(unittest.TestCase):

    def test_jyanken(self):

        # 相手がグーの場合
        expects_guu = {
            1:'あいこです。',
            2:'相手はグーを出しました。あなたの負けです。',
            3:'相手はグーを出しました。あなたの勝ちです。'
        }

        # 相手がチョキの場合
        expects_tyoki = {
            1: '相手はチョキを出しました。あなたの勝ちです。',
            2: 'あいこです。',
            3: '相手はチョキを出しました。あなたの負けです。'
        }

        # 相手がパーの場合
        expects_paa = {
            1: '相手はパーを出しました。あなたの負けです。',
            2: '相手はパーを出しました。あなたの勝ちです。',
            3: 'あいこです。'
        }

        for n,expect in expects_guu.items():
            # 相手の出す手をグーに固定
            result = jyanken.jyanken(n,1)
            self.assertEqual(result,expect)

        for n,expect in expects_tyoki.items():
            # 相手の出す手をチョキに固定
            result = jyanken.jyanken(n,2)
            self.assertEqual(result,expect)

        for n,expect in expects_paa.items():
            # 相手の出す手をパーに固定
            result = jyanken.jyanken(n,3)
            self.assertEqual(result,expect)


if __name__ == '__main__':

    unittest.main(verbosity=2)

相手が出す手がグーの時、自分がグーを出すと→「あいこです。」と出力される

相手が出す手がグーの時、自分がチョキを出すと→「相手はグーを出しました。あなたの負けです。」と出力される

・・・・・

とチョキやパーの場合もfor文を用いて全て確認します。

実行してみるとテストが成功していることがわかります。

test_jyanken (__main__.TestJyanken) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

補足ですが実際にテストを行う場合に全てのパターンをテストすることができないということがあります。

例えば素数を判別するプログラムなどで全ての値をテストしようとしても命がいくつあっても足りません(笑)

その場合はプログラムが正しいと考えられる適切な量でテストするのが良いでしょう。

おわりに

今回はソフトウェア開発を行いたい初心者の方向けに最も簡単な例でテストを解説しました。

unittestを用いることで少し普段とは異なる記述にはなりますが、そんなに難しいものではないということがお分かりいただけたら嬉しいです。

一緒に頑張っていきましょう!

ねこすけ
ねこすけ

その他の記事もおすすめにゃー。

その他の記事

コメント

タイトルとURLをコピーしました