Python
テスト
Jenkins
テスト自動化

Jenkinsさんにお世話になるPython開発 - ユニットテスト編

More than 1 year has passed since last update.

本記事の概要

Pythonを用いた開発において、ユニットテストをJenkinsさんにやってもらう方法を解説する。
Pythonのユニットテストフレームワークとしては、noseかpy.testが候補になりますが
今回は、py.testを使います。

Jenkinsさんには、
* テストの自動実行
* テストレポートの出力
* カバレッジの出力と視覚化
をやってもらいます。

環境は以下の通り。

項目 バージョンなど
Python 3.5.1
Jenkins 1.6...?
テストフレームワーク py.test

py.test

pip install pytestでインストール

テストコードの例

テスト対象コード - calculator.py

class Calculator():
    def add(self, a, b):
        return a + b

    def sub(self, a, b):
        return a - b

    def mul(self, a, b):
        return a * b

    def div(self, a, b):
        return a / b

テストコード - test_calculator.py

import pytest
from calculator import Calculator

def pytest_funcarg__calc():
    return Calculator()

@pytest.mark.parametrize("a, b, r", [(9, 8, 17), (7, 6, 13), (5, 4, 9), (3, 2, 5), (1, 0, 1)])
def test_add(calc, a, b, r):
    assert calc.add(a, b) == r

@pytest.mark.parametrize("a, b, r", [(9, 8, 1), (7, 6, 1), (5, 4, 1), (3, 2, 1), (1, 0, 1)])
def test_sub(calc, a, b, r):
    assert calc.sub(a, b) == r

@pytest.mark.parametrize("a, b, r", [(9, 8, 72), (7, 6, 42), (5, 4, 20), (3, 2, 6), (1, 0, 0)])
def test_mul(calc, a, b, r):
    assert calc.mul(a, b) == r

@pytest.mark.parametrize("a, b, r", [(9, 3, 3), (8, 4, 2), (6, 2, 3), (4, 2, 2), (0, 1, 0)])
def test_div(calc, a, b, r):
    assert calc.div(a, b) == r

def test_div_error(calc):
    with pytest.raises(ZeroDivisionError):
        calc.div(1, 0)

テスト実行

py.testで実行可能
実行したディレクトリ配下を再帰的に探索し、
testで始まるpyファイルを実行してくれる。

テスト結果
成功例

============================= test session starts ==============================
platform darwin -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /Users/rotasuke/git/python_test/others, inifile: 
collected 21 items

test_calculator.py .....................

========================== 21 passed in 0.03 seconds ===========================

失敗例

============================= test session starts ==============================
platform darwin -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /Users/rotasuke/git/python_test/others, inifile: 
collected 21 items

test_calculator.py ...................F.

=================================== FAILURES ===================================
_______________________________ test_div[0-1-1] ________________________________

calc = <calculator.Calculator object at 0x10c9567f0>, a = 0, b = 1, r = 1

    @pytest.mark.parametrize("a, b, r", [(9, 3, 3), (8, 4, 2), (6, 2, 3), (4, 2, 2), (0, 1, 1)])
    def test_div(calc, a, b, r):
>       assert calc.div(a, b) == r
E       assert 0.0 == 1
E        +  where 0.0 = <bound method Calculator.div of <calculator.Calculator object at 0x10c9567f0>>(0, 1)
E        +    where <bound method Calculator.div of <calculator.Calculator object at 0x10c9567f0>> = <calculator.Calculator object at 0x10c9567f0>.div

test_calculator.py:21: AssertionError
===================== 1 failed, 20 passed in 0.04 seconds ======================

Jenkinsジョブ作成

Gitのチェックアウトなどの細かい設定は割愛する。

[ビルド]の[シェルの実行]に
py.test <実行するディレクトリ>
を指定する。

テストレポートの出力

先ほど入力した、実行するシェルスクリプトに
--junitxml=<出力先xmlファイル>
を指定することで、JUnit形式でテストレポートを出力することができる。

[ビルド後の処理]に、[JUnit テスト結果の集計]を追加し
先ほど出力したxmlファイルを指定する。

カバレッジの出力

pip install pytest-covでカバレッジ出力用のモジュールをインストール

先ほど入力した、実行するシェルスクリプトに
--cov-report=xml --cov
を指定することで、コマンド実行したディレクトリ配下にcoverage.xmlを出力することができる。

JenkinsのCobertura Pluginにcoverage.xmlを読ませることで可視化できる。