さるへい備忘録

さるへいのやったことを綴っているブログです。基本的にテクノロジーの話題です。

テスト初心者に贈る〜さるへいが学んだユニットテストの基礎〜(クソ記事)

こんにちは!さるへいです。

いまこの記事は、とある企業のエンジニアブログに載せようとしたら、ひどすぎるといわれてリジェクトされたので、ここに載せている記事です。

つまり!クソ記事です!
温かい目で見て下さいね!

本題としては、テスト初心者の僕が苦心しながら怒られながら身につけたユニットテストの書き方をここに書こうと思います。

テストとは?

ソフトウェアテスト(software test)とは、コンピュータのプログラムを実行し、正しく動作するかどうか確認する作業のことである。(wikipediaより)。

ということで以下に具体的な事例を挙げてみます。

具体例

以下の様なコードがあるとします。

# -*- coding: utf-8 -*-
"""
テスト用サンプル
"""


class SampleForTest:
    """
    自然数判定、負の数判定
    """


    def is_natural_number(self, num):
        """
        自然数を判定する
        """
        if num > 0:
            return True
        else:
            return False


    def is_negative_number(self, num):
        """
        負の数を判定する
        """
        if num < 0:
            return True
        else:
            return False

このプログラムは、

  • 引数が自然数であるか判別する
  • 引数が負の数であるか判別する

ユニットテストを書く

具体的にテストを書いてみます。初心者がここで気になるのは
* ユニットテストの粒度 * どこまでテストを書けばいいのか

だと思います。僕はそうでした。ユニットテストの粒度に関しては、以下の考え方に従ってテストを書きました。

ソフトウェアコンポーネント = メソッドだと捉えてテストを書きました。これにはいろいろ意見があると思いますが、とりあえず僕はそうしています。
また、テストメソッド毎にアサーション一つというよりは、

機能や事象毎にテストが分かれていれば良い

と関口さんたちからご指摘を受けたりもしました。無理に一つにする必要はないとのこと。

また、「どこまでテストを書けばいいのか」という疑問に関しては、具体的な資料などは見つからなかったので、

という結論がでました。できれば同値分割はやったほうがいいとここでもご指摘を頂きました。

個人的には、一番簡単にある程度網羅的なテストを書ける技法だと信じています。

具体的なテストコードとしては、以下のようになります。 ここでは、同値分割だけを行った例を挙げます。

# -*- coding: utf-8 -*-
"""
SampleForTestのテスト
"""
import sample_for_test
import unittest


class TestSamples(unittest.TestCase):
    """
    同値分割のみ実施
    """


    def test_is_natural_number_with_natural(self):
        """
        is_natural_numberのテスト。自然数が入力されたら返り値はTrue
        """
        obj = sample_for_test.SampleForTest()
        self.assertTrue(obj.is_natural_number(3))

    def test_is_natural_number_with_negative(self):
        """
        is_natural_numberのテスト。負の数が入力されたら返り値はTrue
        """
        obj = sample_for_test.SampleForTest()
        self.assertFalse(obj.is_natural_number(-4))


    def is_negative_number_with_negative(self):
        """
        is_negative_numberのテスト。負の数が入力されたら返り値はTrue
        """
        obj = sample_for_test.SampleForTest()
        self.assertTrue(obj.is_negative_number(-4))

    def is_negative_number_with_natural(self):
        """
        is_negative_numberのテスト。自然数が入力されたら返り値はFalse
        """
        obj = sample_for_test.SampleForTest()
        self.assertFalse(obj.is_negative_number(3))


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

本当は、stringが入力として渡ってきた場合のテストもしなければいけない気がしますが、それはまぁ割愛で。

まとめ

ざっくり言ってしまうと。 * テストの粒度 * 機能や事象毎にテストを分ける * どこまでテストを書けばよいのか * 同値分割。できれば境界値分析

とするのが良いことということが実際に内定者研修をしながら実感した内容でした。

テストを書くことにおける@A01saruの考え

ソフトウェアテストとは、ソフトウェアの品質保証の一環です。
そして、僕がある本を読んだ際に非常に感銘を受けた言葉があります。

「品質」とはソフトウェア製品の顧客満足度そのもの

つまり、テストとは顧客満足度を向上させるためのものであり、極論ですが、テストのない製品は顧客を満足させることができないと考えることができます。顧客を満足させるためはやはりテストは必要だと僕は考えます。

なのでテストはめんどくさいと考える皆さんも、テストを書いたことのないエンジニアの卵の皆さんもテストを書いて満足してもらえるようなアプリをつくりましょう!