31:過剰なmockを避ける¶
mock は便利なライブラリですが、使いすぎには要注意です。
mockでよくある失敗から、ベストプラクティスを学びましょう。
具体的な失敗¶
DjangoのView関数をテスト対象として考えます。
from .forms import PostSearchForm
from .posts import search_posts
def post_list(request):
if request.GET:
form = PostSearchForm(request.GET)
if form.is_valid():
text = form.cleaned_data['search']
posts = search_posts(text)
else:
form = PostSearchForm()
posts = Post.objects.all()
return TemplateResponse(request, 'post_list.html',
{'posts': posts, 'form': form})
このView関数のテストとして mock を使いすぎると、次のようになります。
from unittest import mock
from django.test import TestCase
class TestPostList(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 '本文' in res.content.decode()
この例ではView関数の動作のみをテストするためにmockを乱用しています。
しかし、このテストから確認できることは、ほぼありません。
search=本文
のように指定されたクエリーパラメーターが正しくフォームで解釈されて、検索に使われて、テンプレートに描画されるつながりを確認できないからです。
ベストプラクティス¶
mockを使いすぎるよりも、単純にデータを作成して動作確認をするほうが良いでしょう。
class TestPostList(TestCase):
def test_search(self):
PostFactory(title='タイトル')
PostFactory(title='テスト')
res = self.client.get('/posts', data={'search': 'タイトル'})
assert "タイトル" in res.content.decode()
assert "テスト" not in res.content.decode()
(中略)詳細は書籍 自走プログラマー をご参照ください