色々なテストコードを作成してみよう の講座の2レッスン目。
今回は関数やクラスのテスト方法を学んでいきます。
前回のレッスンはこちら↓
前回はお前が作ったクソ日記アプリをベースに
表示項目のテストをやったんだったな
ちょいちょい悪口挟んでくるのはなんなの?
今回は関数やクラスのテストを書いてみるぞ
テスト対象の準備
日記アプリに機能を追加し、テストを書いてみる。
さっそく準備をしていこう。
リポジトリのクローン
まずはベースとなる日記アプリのリポジトリをクローンする
$ git clone https://github.com/yheihei/base_diary.git
$ cd base_diary
テストコードだけ見る場合
今回もテストコードを書いたブランチを予め用意しておいた。
答えだけ先に見たいやつは下記コマンドでチェックアウトしてくれ
# テストコードがすでに書いてあるブランチを見たい場合はこちら
$ git fetch && git checkout feature/#2
テスト対象の解説
もう一度この日記アプリの画面表示を見てみよう。
トップページにアクセスすると、こんな画面が出てくる
仕様は下記。
- トップページにアクセスすると、日記一覧が表示される
- 各日記には下記が表示される
- タイトル
- 投稿者
- 本文
- 投稿日
- カテゴリー
今回実装する機能
今回は一覧に表示する日記件数を指定する機能を作ってみる。
完成イメージは下記だ。
per_page=件数 というクエリストリングを指定すると、一覧に表示する日記件数を絞ることができる。
クラスベースビューのListViewを使うと一瞬で実装できるんだが
今回はあえて自分でそういう機能を作って、テストをしてみるぞ。
機能追加する
では機能を作ってみるぞ。
diary/views.py
をいじる。
from django.shortcuts import render
# Create your views here.
from .models import Post
# Create your views here.
def index(request):
return render(request, 'index.html', {
'posts': Post.objects.all(),
})
ここにロジックをベタで書いてもいいが
viewsの中にロジックがひたすら肥大して行くのは微妙だ。
なのでServiceクラスに切り出すぞ。
こんな感じだ。
from django.shortcuts import render
from .services import IndexViewAppService
# Create your views here.
from .models import Post
# Create your views here.
def index(request):
posts = IndexViewAppService(request).create_context()
return render(request, 'index.html', {
'posts': posts,
})
from django.http import HttpRequest
from .models import Post
from typing import List, Dict
class IndexViewAppService:
'''
トップページに表示するcontextを作成する
'''
def __init__(self, request: HttpRequest) -> None:
self.request = request
def create_context(self) -> List[Post]:
posts = Post.objects.all()
# 件数指定があればlimitをかける
per_page = self.request.GET.get('per_page')
if per_page:
return posts[:int(per_page)]
return posts
request
を受け取って、件数指定があればレコード取得時に
posts[:int(per_page)]
って件数指定するんだね
この状態でトップページを見ると、
per_pageで件数が絞り込まれてる。OKだ
テストコードを書く
では、テストコードを書いてみる。
今回は「関数やクラスについてテストする」だったな。
今我々は、日記表示のロジックが書かれた、IndexViewAppService
クラスを定義したわけだ。
IndexViewAppService
の仕様は
- requestを受け取って
- requestの中に
- per_pageがあれば、per_pageで絞り込んだPostレコードを返す
- なければ、Postレコードを全件返す
だ。
これをテストコードに反映してみよう。
完成系は下記だ。
from django.test import TestCase
from django.urls import reverse
from django.http import HttpRequest
from .services import IndexViewAppService
# Create your tests here.
class TestIndexView(TestCase):
'''#2 関数を自動テストする'''
# テスト用データを投入する
fixtures = ['diary/fixtures/test/test_index_view.json']
def setUp(self):
pass
def test_2(self):
'''件数指定でリクエストを渡すとその件数で記事一覧を返す'''
request = HttpRequest()
request.GET['per_page'] = "1"
posts = IndexViewAppService(request).create_context()
# 1つ記事が取得されている
self.assertEqual(len(posts), 1)
↓最初にIndexViewAppService
とリクエストを作成するのに必要なモジュールをimportしておく。
from django.http import HttpRequest
from .services import IndexViewAppService
↓次にper_page
に1を入れたrequest
を作る。
def test_2(self):
'''件数指定でリクエストを渡すとその件数で記事一覧を返す'''
request = HttpRequest()
request.GET['per_page'] = "1"
↓IndexViewAppService
にrequest
を入れてやり、create_context
を叩いてposts
を取得する。
posts = IndexViewAppService(request).create_context()
↓その記事数が1になってればOK。
# 1つ記事が取得されている
self.assertEqual(len(posts), 1)
これでIndexViewAppService
のメソッドに対してテストしたことになるのか
最後にテストを実行してみるぞ。
$ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.020s
OK
無事テストが通った!
関数やクラスをテストする方法まとめ
今回は、関数やクラスをテストする方法を学んだな
posts = IndexViewAppService(request).create_context()
self.assertEqual(len(posts), 1)
使いたいモジュールをimportして、assertで期待値をとるだけだったね
前回のClientクラスを使ったテストは、一つの業務フローのINとOUTだけを確認する大きなテスト。
関数やクラスのテストは、大きなテストもできるし、
本当に小さな関数をチマチマテストすることもできる
用途によって使い分けていくといいんだね
今回は以上!
次はバッチ系の自動テストを考えていくからな。
復習しとけよ。
\ 講座で学んだことを即アウトプットしよう /
次の講座
Djangoの基礎を学びたい方は
Djangoの基礎を固めたい方はこちら(セール時に買うのがおすすめ)
『Djangoパーフェクトマスター』〜インスタ映えを支えるPython超高速開発Webフレームワークを徹底解説!
動画講座で手を動かしながら、ほとんどのことが学べます。
ウサギもここから始めました。
コメント
[…] 関数やクラスを自動テストするDjango自動テスト講座第二弾! 関数やクラス… ウサギ […]