mtbの学んだことのブログ

とあるPythonエンジニアのブログ

pytestでdjangoのcoverageを測る

pytestでcoverageを測りたい。そうすれば、色々スピードアップする予感がある。

とりあえず、やってみた話。

venv環境を作る

$ python3.6 -m venv coverage
$ . coverage/bin/activate
(coverage) $ python -V
Python 3.6.5

pytestでテストできるようにする

とりあえず、pytestでテストできるようにしとく。

(coverage) $ pip install pytest
(coverage) $ pip freeze | grep pytest
pytest==3.5.1

test_my_module.py

import my_module

def test_case_1():
    source = 1
    result = my_module.function1(source)
    assert str(source) == result

my_module.py

def function1(x):
    return str(x)
(coverage) $ pytest test_my_module.py
===================================== test session starts =====================================
platform darwin -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /Users/mtb/work/coverage/work, inifile:
collected 1 item

test_my_module.py .                                                                     [100%]

================================== 1 passed in 0.00 seconds ===================================

OK

pytest-covを使う

まず、インストールする。

(coverage) $ pip install pytest-cov
(coverage) $ pip freeze | grep  pytest-cov
pytest-cov==2.5.1

そして実行する。

(coverage) $ py.test --cov my_module
=============================================================== test session starts ===============================================================
platform darwin -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /Users/mtb/work/coverage/work, inifile:
plugins: cov-2.5.1
collected 1 item

test_my_module.py .                                                                                                                         [100%]

---------- coverage: platform darwin, python 3.6.5-final-0 -----------
Name           Stmts   Miss  Cover
----------------------------------
my_module.py       2      0   100%


============================================================ 1 passed in 0.02 seconds =============================================================

便利だ。

カバレッジ下げてみる

あえて、カバレッジが下がりそうなことをしてみる。

def function1(x):
    return str(x)

def function2(x):
    if x == 1:
        return True

    return False
(coverage) $ py.test --cov my_module
=============================================================== test session starts ===============================================================
platform darwin -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /Users/mtb/work/coverage/work, inifile:
plugins: cov-2.5.1
collected 1 item

test_my_module.py .                                                                                                                         [100%]

---------- coverage: platform darwin, python 3.6.5-final-0 -----------
Name           Stmts   Miss  Cover
----------------------------------
my_module.py       6      3    50%


============================================================ 1 passed in 0.02 seconds =============================================================

OK. カバレッジ下がった。

テストを追加する。

import my_module

def test_case_1():
    source = 1
    result = my_module.function1(source)
    assert str(source) == result

def test_case_2():
    source = 1
    result = my_module.function2(source)
    assert result == True

def test_case_3():
    source = 2
    result = my_module.function2(source)
    assert result == False
(coverage) $ py.test --cov my_module
=============================================================== test session starts ===============================================================
platform darwin -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /Users/mtb/work/coverage/work, inifile:
plugins: cov-2.5.1
collected 3 items

test_my_module.py ...                                                                                                                       [100%]

---------- coverage: platform darwin, python 3.6.5-final-0 -----------
Name           Stmts   Miss  Cover
----------------------------------
my_module.py       6      0   100%


============================================================ 3 passed in 0.03 seconds =============================================================

100%になった。

djangoでpytestでカバレッジを図る

djangoでもカバレッジ測りたい。というわけで測ってみる。

djangoの準備

django 初心者だから1.11にしとく。

(coverage) $ pip install django==1.11
(coverage) $ django-admin startproject myproject
(coverage) $ cd myproject/
(coverage) $ ls
manage.py myproject

そして、雑なレスポンスを返すように修正。

myproject/url.py

from django.conf.urls import url
from django.contrib import admin
from django.http.response import HttpResponse

def index(request):
    return HttpResponse('Hello Djano')


urlpatterns = [
    url(r'^', index),
    url(r'^admin/', admin.site.urls),
]

雑に動作確認して動くことを確認。d

(coverage) $ python manage.py runserver
$ curl http://localhost:8000
Hello Djano

pytestでdjangoをテスト

pytest-djangoをインストールする。バージョンは現時点の最新版。

(coverage) $ pip install pytest-django
(coverage) $ pip freeze | grep pytest-django
pytest-django==3.2.1

pytest.iniという設定ファイルを追加

[pytest]
DJANGO_SETTINGS_MODULE = myproject.settings
python_files = tests.py test_*.py *_tests.py

テストを追加。

myproject/tests.py

from django.test import TestCase, Client

class IndexTest(TestCase):
    def test_http(self):
        client = Client()
        response = client.get('/')
        self.assertEqual(response.status_code, 200)

テストを実行。

(coverage) $ pytest
=============================================================== test session starts ===============================================================
platform darwin -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
Django settings: myproject.settings (from ini file)
rootdir: /Users/mtb/work/coverage/work/myproject, inifile: pytest.ini
plugins: django-3.2.1, cov-2.5.1
collected 1 item

myproject/tests.py .                                                                                                                        [100%]

============================================================ 1 passed in 0.20 seconds =============================================================

テストできた。

pytest + django + coverage

とりあえず指定したらできた。

(coverage) $ pytest --cov myproject
=============================================================== test session starts ===============================================================
platform darwin -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
Django settings: myproject.settings (from ini file)
rootdir: /Users/mtb/work/coverage/work/myproject, inifile: pytest.ini
plugins: django-3.2.1, cov-2.5.1
collected 1 item

myproject/tests.py .                                                                                                                        [100%]

---------- coverage: platform darwin, python 3.6.5-final-0 -----------
Name                    Stmts   Miss  Cover
-------------------------------------------
myproject/__init__.py       0      0   100%
myproject/settings.py      18      0   100%
myproject/tests.py          6      0   100%
myproject/urls.py           6      0   100%
myproject/wsgi.py           4      4     0%
-------------------------------------------
TOTAL                      34      4    88%


============================================================ 1 passed in 0.27 seconds =============================================================

ふむ。測れてそう。

ちなみに、coverageを図るパッケージは指定しないと、全範囲が対象になって、時間がかかるし、大量に出てくる。

終わり

とりあえず、djangoをpytest使ってcoverage測れるようにあった。

実際の仕事でもどんどん使って行こう。