1. 推奨するテストの典型例
本当は’factory’を利用するパターンも記載しておきたいんだが、ちょっと長くなる事やDjango専用になってしまうことから今回は避ける。
1.1. pytestにおける典型例
""" 推奨するテストの典型例
"""
import pytest
import responses
class TestCase:
@pytest.mark.parametrize("text", ["a", "a" * 50, "a" * 100])
def test_param(text):
""" パラメータ(テストデータ)は異なるがテスト内容は同じ場合に有効
"""
# 準備
from test_target import validate
# 検証
assert validate(text)
@pytest.fixture
def target_api(self):
""" データベースのセットアップ等の共通の準備を定義する
scope引数で以下の値により適用範囲を指定可能(デフォルトは'function')
・function: テストケースで適用
・class: テストクラスで適用
・module: テストファイル内で適用
・session: テスト全体で適用
"""
return "/api/signulp"
def test_fixture(self, target_api, django_app):
""" ここでは共通準備を定義せずに、上記'fixture'に任せる
"""
# 準備
test_path=target_api
# 実行
res=django_app.post_json(test_path)
# 検証
assert res.status_code == 201
@responses.activate
def test_post(self):
""" 外部へのWebリクエストをモックする
"""
# 準備
from test_target import post_to_sns
responses.add(responses.POST, 'http://domain.example.com/posts', json={'body': 'レスポンス本文'})
# 実行
data = post_to_sns("投稿の本文")
# 検証
data['body'] == 'レスポンス本文'
def test_CONST_VAL(self):
""" テスト対象内の定数をモックしたい場合
"""
# 準備
from unittest import mock
from test_target import is_enough_spam
# 実行
with mock.patch("hoge.NUM_OF_SPAM", new=1):
actual = is_enough_spam()
# 検証
assert actual == True
def test_raises(self):
""" 仕様通りに例外が発生するか検証
"""
# 検証
with pytest.raises(TypeError):
sum([1, None])
1.2. ファイルに関するテストの典型パターン
‘setup_method’と’teardown_method’が要としている。
‘setup_method’はテストの最初に実行され、ここではファイルの作成やファイル内容の定義を行っている。
‘teardown_method’はテストの最後に実行され、ここではファイルを閉じている。
""" ファイルに関するテストの典型パターン
"""
class TestCaseFile:
def setup_method(self, method):
""" テストケース毎に最初に実行される
"""
import tempfile
self.test_fp = tempfile.NamedTemporaryFile(mode='w', encoding="utf-8")
self.test_csv = self.test_fp.name
self.test_fp.writelines([
'Spam,Ham,Egg\n',
'Spam,Ham,Egg\n',
'Spam,Ham,Egg\n',
'Spam,Ham,Egg\n',
'Spam,Ham,Egg\n',
])
self.test_fp.seek(0)
def teardown_method(self, method):
""" テストケース毎に最後に実行される
"""
self.test_fp.close()
def test_import(self):
""" このテストケースの前に'setup_method'が実行される
このテストケースの後に'teardown_method'が実行される
"""
# 準備
from test_target import import_csv, Spam
# 実行
import_csv(self.test_csv)
# 検証
assert Spam.objects.count() == 5
2. テストケースのバッドケース
2.1. 過剰なモックの使用
パッと見で以下を理解できうるだろうか…。私には無理だ。
""" テストケースのバッドケース
"""
from django.test import TestCase
from unittest import mock
class TestBadCase(TestCase):
@mock.patch('posts.search_posts', return_value=[{'title': 'タイトル', 'body': '本文'}])
@mock.patch('forms.PostSearchForm')
def test_search(self, m_search, m_form):
""" 過剰なモックを使用すること
・客観的に何をしているか不明(助長なテストコード)
"""
# 実行
with mock.patch.object(m_form, 'is_valid', return_value=True):
res = self.client.get('/posts', data={'search': '本文'})
# 検証
assert res == '本文'