文系データサイエンティスト怒天龍爆男のブログ

初心者向きソフトウェアのテスト手法紹介(「はじめて学ぶ ソフトウェアのテスト技法」要約)

先日ソフトウェアのテストに関する本を読んだため、その内容を簡単に整理したいと思います!

はじめて学ぶソフトウェアのテスト技法

はじめて学ぶソフトウェアのテスト技法

 
 仕事でPythonスクリプトのテストをする機会があったのですが、テスト自体全くやったことがなかったため詰められてしまい、反省の念から読むことにしました。🤗

僕自身が全くの初心者であるため、以下の内容は超簡単な、テストをやったことがない人向けのものになっているかと思いますがご容赦ください!

テスト概要

テストとはソフトウェアにバグがないかを確認するものですが、一般にバグがないプログラムを作成することはほとんど不可能なものらしいです。

また、ソフトウェアが実際に行う可能性のある全ての挙動を確認することも実質的に不可能だと言われています。

例えば「与えられた整数の絶対値を返すソフトウェア」があったとして、このソフトウェアの挙動全てを確認するには、この世にある全ての数に関して動作をさせなければなりません。

今回紹介していくテスト手法は、そうした無限に存在するテストケースの中から、効率よく、網羅的なテストを実施するための、テストケースのサブセットの作成方法を提供するものとなっています。

テストのレベルに関して
データサイエンティストとしては、実際に行うのは下記の「単体テスト」、「結合テスト」くらいかと思いますが、テスト全体のレベル構成としては以下のようになっています。

ソフトウェアの最も小さい部品に対して行うテストです。基本的には1人のプログラマの成果物、1個のファイルが対象の粒度となるようです。

単体テストを行ったシステムをサブシステムとして結合したシステムに対して行うテストです。

顧客に届ける製品を作り上げている全てのソフトウェアを結合した、最も高いレベルの統合システムに対して行うテストです。

  • 受け入れテスト

顧客が実際にソフトウェアを受け入れる際に問題がないかを確認するテストです。

システム設計とテスト

テストを行う際には、対象となるシステムがどのような設計で開発されたかということが重要となります。特に、「契約による設計」と「防御的設計」では行うテストが大きく変わります。

前者の場合、システムが正常に動作するために必要な事前条件が整っている、という前提を置いています。「与えられた整数の絶対値を返すソフトウェア」の場合、「入力がまともな整数(-1, 10など)」といった仮定を置いたテストを行うことになります。

後者の場合はその逆で、「与えられた整数の絶対値を返すソフトウェア」のテストとして「入力が整数か」といったこともテストを行う必要があります。

以下ではよりシンプルな「契約による設計」に基づいたテストについて説明していきます。

ブラックボックステスト

ブラックボックステストとは、要件と仕様書に基づき行うテストのことです。「ホワイトボックステスト」との違いとして、ブラックボックステストではテスト対象ソフトウェアの内部パス、構造、実装を知らない状態で行うものだという点が挙げられます。
また、ホワイトボックステストは、「全スクリプトのうちどのくらいの部分を実際にテストできたか」「全制御フロー(if分とかで分岐するやつ)のうちどのくらいテストできたか」といった「カバレッジ」に関連したテストとなります。(今回は省略します)

同値テスト

モジュールで同等に処理されるデータ、あるいは同じ結果を返すデータの集合を「同値クラス」といい、「同値クラスごとに1つのテストケースのみ作成する」方法を「同値テスト」と言います。「与えられた整数の絶対値を返すソフトウェア」の場合、正の整数が同値クラスとなり、正の整数、0、負の整数それぞれの同値クラスに対して3個のテストケースがあれば十分ということになります。

境界値テスト

同値クラス同士の境界に関して行うテストです。経験的に同値クラスの境となる部分に関してエラーが多いということが一般に知られており、それに対応する為のテストとなります。例えば「与えられた整数の絶対値を返すソフトウェア」の場合、以下のような間違いをする可能性があります。

def get_abs(num):
if num > 0:

   return num

#以下間違い部分!

elif num <= 0:

   return -num

else:

   return 0

境界値テストと同値テストの手法を適応した場合、テストケースは「0」「1」「-1」となります。

ディシジョンテーブルテスト

ディシジョンテーブルとは複雑なビジネスロジックを整理した表のことで、具体的には以下のようになります。

入力 ルール1 ルール2 ルール3 ルール4
条件1:手持ちの現金が十分か Yes Yes No No
条件2:ガッツリ飲みたいか Yes No Yes No
アクション1:トリキに行く No Yes No Yes
アクション2:鳥メロに行く Yes No Yes No
アクション3:お金を下ろす No No Yes No

それぞれのルールに対して、境界値テストなどの手法を用いて1つ以上のテストケースを作成することになります。

 

 

以上、簡単になってしまいましたが初心者向きソフトウェアのテスト手法紹介でした!

Pythonの高度な関数(Effective Python, エキスパートPythonプログラミング要約)

最近上司に「Python詳しくなってよ〜」と言われたので、Pythonの本を2冊読んでみました!
 

Effective Python ―Pythonプログラムを改良する59項目

Effective Python ―Pythonプログラムを改良する59項目

エキスパートPythonプログラミング改訂2版

エキスパートPythonプログラミング改訂2版

2冊とも内容は結構似ていたのですが後者の方が難しかった印象です。

ちなみに上記の「Effective Python」は、オライリーの「Effective Software Development」シリーズのPython版みたいです。

文系の私には2冊とも難しくて正直クラスとかメタクラスとかの内容はさっぱりわからなかったので、せめてもの抵抗として関数部分についてのみ備忘録として整理したいと思います😁

 

リストを返さずにジェネレーターを返す

ジェネレーターとはyield式を使う関数のことです。
例えば、以下のようにある値numまでの数値を二乗して表示するコードがあるとします。

コード:

def get_list_for_loop(num):
   
   list_for_loop = []

   for i in range(num):
   
      list_for_loop.append([round(i**0.5, 2), i**2])

   return list_for_loop

for i in get_list_for_loop(500):
   print(i)
                        

結果:

>>> 
[0.0, 0]
[1.0, 1]
[1.41, 4]
[1.73, 9]
.
.

このget_list_for_loopのようにリストを返す関数は、以下のようにジェネレーターで書き換えられます。

def gen_for_loop(num):
   
   for i in range(num):
   
      yield [round(i**0.5, 2), i**2]
   
for i in get_list_for_loop(500):
   print(i)

結果:

>>> 
[0.0, 0]
[1.0, 1]
[1.41, 4]
[1.73, 9]
.
.

ジェネレーターを使うことのメリットとして、以下のものがあるようです。

  • リストを操作するコード部分が減り、可読性が上がる
  • リストを返す関数にすると、一度にリストを完成させてしまう為、リストが大きい時にメモリを圧迫してしまう。ジェネレーターは逐次的に計算する為、上記の問題を避けられる。

関数をみた時にreturnじゃなくてyieldになってるとかっこいいので僕も暇な時使ってみたいと思います。😁

デコレーターを使って関数をラップする

デコレーターを使うと簡単に関数のラップ(機能追加)ができます。

def deco(func):
    def wrapper(*args, **kwargs):
        print("引数表示", *args, **kwargs)
        func(*args, **kwargs)
    return wrapper

@deco
def test(person):
    print('Hello {}'.format(person))

test("bakuo")

結果:

>>> 
引数表示 bakuo
Hello bakuo


この例のように関数の前後に何らかの処理を挟むことができます。
関数アノテーションなどと組み合わせると型チェックなどもできるようなので、「Pythonに型チェックないのキモいから自分で実装しちゃった😅」とか言えそうでいいですよね〜(僕はpythonとRしかやったことないのでその感覚がわからないですが。)


以上、簡単にはなってしまいましたがPythonの高度な(?)関数の紹介でした!