こんにちは、Zero-Cheeseです。
私は社会人になってから、独学でプログラミングを学習した者です。
独学で勉強していると、つい見落としがちなのが、コードの品質になります。
私は、ソフトウェア部署への異動面談で以下のやりとりをしました(笑)
面接官:「ソフトウェアの品質担保、つまり品質工学の技術はどれ位お持ちですか?」
私:「(品質工学・・・ 初めて聞いた・・・・ えべ・・。)あの、えと(汗)・・」
面談位なら、慌てて終わるだけで済みますが、ソフトウェア品質が担保できないと、色々な所に迷惑をかけたりして、大変です。(ホントに・・・)
本記事では、品質担保の1つであるソフトウェアテストの、導入方法から実行までをご紹介致します。
コードのユニット単位で、テストにより品質を保証した後に、次のコードを書く癖をつけると、心理的な安心感が全然違ってきます!
前提
この記事では、「pytest」を紹介します。
pythonには標準で使用できる「unittest」がありますが、「pytest」が上位互換のため、こちらを学ぶのがベターです。
unittestで作ったコードでも、pytestから実行できるよ!
pytestのインストール方法を紹介した後、PyCharm上からの実施方法、コマンドからの実施方法の順番で、ご紹介します。
インストール方法
pipでインストール可能です。
pip install pytest
テスト手順
テストされる側のコードを準備
まずは、ソフトウェアとして必要なコードを作ります。(テスト駆動を採用している場合は、先にテストから作ります。)
例えば下記のコードがあったとします。
(本記事では、IDEとして、PyCharmを使用した例をご紹介します。)
テストコードの準備
次にテストファイルを作ります。
名前は「test_〇〇.py」のようにtest_から初めるのがお約束です。
〇〇は任意名でOKですが、後で振り返って、何のテストをしているのか分かる名前にします。(ここでは、 test_add_functionにしました。)
テストコードの作成
まずは、クラスを使わない方法をご紹介します。
# ⬇テストされる関数の呼び出し (先程、自作したコード)
from add_function import add
def test_add(self):
assert add(10, 5) == 15
# ⬆ if文の条件式を書くような感じで書ける
次にクラスを使用した方法です。この方法を覚えておく方が、応用が効くと思います。
# ⬇テストされる関数の呼び出し
from add_function import add
class TestAdd(object):
def test_add(self):
assert add(10, 5) == 15
unitetestの場合、unittest.TestCaseを継承する必要がありますが、pytestの場合は不要です。
クラス名は「Test〇〇」がお約束です。
〇〇は任意名です。
メソッド名は、「test_△△」がお約束です。△△も何でもOKです。
テスト実行手順(PyCharm版)
PyCharm上での手順をご紹介します。(のちほど、コマンドからの実行例を紹介します。)
まずは、Edit Confiurationsをクリックします。(メニューバーからは、[Run] > [Edit Configurations])
MACの場合、下図の矢印になります。(windowsの場合、もう少し右にあります。)
次に、下記のダイアログが出現します。左上の+を押します。
一覧の中から、「pytest」を選択します。
次に、テストの「Target」と、作業場所「Working directory」を埋めればOKです。(下図の矢印部参照
記入後、右下の「OK」ボタンを押します。
そして下記ボタンを押して実行します。すると画面下部にテストがOKだった事が示されます。
参考までに、NGの場合は以下の画面が出現します。(IDE画面下の部分のみ表示)
テスト実行手順(コマンド版)
コマンドプロンプトから実行する場合は、以下の通りです。
# ファイル名を指定して実行
pytest ファイルパス
# 例)pytest test_add_function.py
# フォルダを指定して実行
# フォルダに含まれるテストは全て実行されます。
pytest フォルダパス
# 例)pytest ./
実行すれば、下記のような結果が返ってきます。
その他、知っておくと便利な機能
テストの開始前、開始後に実行されるコードの書き方をご紹介します。
以下の順番で、ご紹介いたします。
- 各テストメソッドの開始前、開始後に実行されるコードの紹介
- テスト全体で開始前、開始後に1度だけ実行されるコードの紹介
前提として、下記コードのように、複数のテストメソッドを持つクラスがあったとします。
# ⬇テストする関数を呼び出し
from add_function import add
class TestCalculation(object):
def test1(self):
assert add(10, 5) == 15
def test2(self):
assert add(10, -1) == 9
各テストメソッドの開始前、開始後に実行されるコード
下記コードの、「setup_method」が開始前、「teardown_method」が開始後に実行されます。
下記コードの場合、test1とtest2の前後で実行されます。
class TestCalculation(object):
def setup_method(self, method):
print('各テスト実行前')
def teardown_method(self, method):
print('各テスト実行後')
def test1(self):
assert add(10, 5) == 15
def test2(self):
assert add(10, -1) == 9
テスト全体で開始前、開始後に1度だけ実行されるコードの紹介
「setup_class」が全体開始前、「teardown_class」が全体終了時に実行されます。
class TestCalculation(object):
@classmethod
def setup_class(cls):
print('開始前に実行')
@classmethod
def teardown_class(cls):
print('終了時に実行')
def test1(self):
assert add(10, 5) == 15
def test2(self):
assert add(10, -1) == 9
更に深い使用方法が必要な方へ
次回の記事では、更に深いpytestの使い方をご紹介します。
具体的には、conftest、fixture、カバレッジ、mock、またFlaskを使った際のDBテスト方法を記す予定です。
近日中に公開します。
公開しました。
雑談
私は初めてユニットテストを知った時に、どうして莫大な労力を使って、テストコードを書く必要があるのか、全然理解できていませんでした。
一回、痛い目に会って、テストの価値が分かりました(笑)
皆様は、私と同じ間違いを起こさない事を祈るばかりです。(まあ普通の会社ならば、どこまでテストするべきか、ルールがあるとは思いますが・・)
また、「どんなテストを書いたらいいんだろう?」と思ってる方もいるかと思います。
以前、テスト技法という事でご紹介させて頂きました。
もしご興味がありましら、参考にして頂ければと思います。
最後まで読んで頂き、ありがとうございました。