関数やクラスを自動テストする

関数やクラスの自動テスト-Django色々なテストコードを作成してみよう

↓↓↓はじめて講座を受ける方はこちら↓↓↓
開発環境を作ろう

色々なテストコードを作成してみよう の講座の2レッスン目。

今回は関数やクラスのテスト方法を学んでいきます。

前回のレッスンはこちら↓

ウサギ
ウサギ

前回はお前が作ったクソ日記アプリをベースに

表示項目のテストをやったんだったな

わいへい
わいへい

ちょいちょい悪口挟んでくるのはなんなの?

ウサギ
ウサギ

今回は関数やクラスのテストを書いてみるぞ

テスト対象の準備

日記アプリに機能を追加し、テストを書いてみる。

さっそく準備をしていこう。

リポジトリのクローン

ウサギ
ウサギ

まずはベースとなる日記アプリのリポジトリをクローンする

GitHub - yheihei/base_diary: ウサでも分かる中級Django講座の教材
ウサでも分かる中級Django講座の教材. Contribute to yheihei/base_diary development by creating an account on GitHub.
$ git clone https://github.com/yheihei/base_diary.git
$ cd base_diary

テストコードだけ見る場合

ウサギ
ウサギ

今回もテストコードを書いたブランチを予め用意しておいた。

答えだけ先に見たいやつは下記コマンドでチェックアウトしてくれ

GitHub - yheihei/base_diary at feature/#2
ウサでも分かる中級Django講座の教材. Contribute to yheihei/base_diary development by creating an account on GitHub.
# テストコードがすでに書いてあるブランチを見たい場合はこちら
$ git fetch && git checkout feature/#2

テスト対象の解説

ウサギ
ウサギ

もう一度この日記アプリの画面表示を見てみよう。

トップページにアクセスすると、こんな画面が出てくる

クソ日記アプリ

仕様は下記。

  • トップページにアクセスすると、日記一覧が表示される
  • 各日記には下記が表示される
    • タイトル
    • 投稿者
    • 本文
    • 投稿日
    • カテゴリー

今回実装する機能

今回は一覧に表示する日記件数を指定する機能を作ってみる。

完成イメージは下記だ。

per_page=件数 というクエリストリングを指定すると、一覧に表示する日記件数を絞ることができる。

per_page=1の場合1件表示
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=1の場合1件表示
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"

IndexViewAppServicerequestを入れてやり、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フレームワークを徹底解説!

動画講座で手を動かしながら、ほとんどのことが学べます。

ウサギもここから始めました。

コメント

  1. […] 関数やクラスを自動テストするDjango自動テスト講座第二弾! 関数やクラス… ウサギ […]

タイトルとURLをコピーしました