2018年7月28日土曜日

flasgger で unittest

概要

flasgger で作成したアプリを unittest でテストしてみました
アプリは Marshmallow Schemas で作成しています
Mock との連携方法も紹介します

環境

  • macOS X 10.13.6
  • Python 3.6.5
  • flasgger 0.9.0

テスト対象のアプリ

  • vim test_app.py
# coding: utf-8
from flask import Flask, jsonify
from flasgger import Schema, Swagger, SwaggerView, fields


class CategorySchema(Schema):
    id = fields.Int()
    name = fields.Str(required=True)


class PetSchema(Schema):
    category = fields.Nested(CategorySchema, many=True)
    name = fields.Str()


class RandomView(SwaggerView):
    summary = 'A cute furry animal endpoint.'
    description = 'Get a random pet'
    parameters = [
        {
            'name': 'id',
            'in': 'path',
            'required': True,
            'type': 'integer'
        }
    ]
    responses = {
        200: {
            'description': 'A pet to be returned',
            'schema': PetSchema
        }
    }

    def get(self, id):
        pet = self.external_api(id)
        return jsonify(PetSchema().dump(pet).data)

    def external_api(self, id):
        return {'category': [{'id': id, 'name': 'rodent'}], 'name': 'Mickey'}


app = Flask(__name__)
app.add_url_rule(
    '/random/<id>',
    view_func=RandomView.as_view('random'),
    methods=['GET']
)


if __name__ == '__main__':
    app.run(debug=True)

こんな感じのアプリです
/random/1 に GET すると適当な JSON が返ってきます

普通に unittest でテストする

  • vim test1.py
import unittest
import json
import test_app

class TestApp(unittest.TestCase):
    def setUp(self):
        self.app = test_app.app.test_client()

    def testGet(self):
        res = self.app.get('/random/1')
        self.assertEqual(
            {'category':[{'id':1,'name':'rodent'}],'name':'Mickey'},
            res.get_json()
        )

if __name__ == '__main__':
    unittest.main()
  • pipenv run python3 -m unittest test1.py

ポイントは test_app.app.test_client() で Flask アプリ用のクライアントを作成している点です
このクライアントの get や post といったメソッドをコールすることでアプリにリクエストすることができます

Mock を使ってテストする

次に unittest.MagicMock を使ってテストします
external_api というメソッドを Mock してみたいと思います

  • vim test2.py
import unittest
from unittest.mock import patch, MagicMock
import json
import test10

class TestApp(unittest.TestCase):
    def setUp(self):
        self.app = test10.app.test_client()

    @patch('test10.RandomView.external_api')
    def testMockGet(self, mock):
        mock.return_value = {'category':[{'id':100,'name':'rodent'}],'name':'Mickey'}
        print(mock)
        res = self.app.get('/random/1')
        self.assertEqual(
            {'category':[{'id':100,'name':'rodent'}],'name':'Mickey'},
            res.get_json()
        )

if __name__ == '__main__':
    unittest.main()

ポイントは @patch('test10.RandomView.external_api') です
関数まで patch 当てます
すると引数の mock に MagicMock クラスのオブジェクトが返ってきます
更に mock は patch のおかげで関数にもなっているのであとは return_value で返り値を設定するだけです

今回は id:100 を Mock が返すように設定しています

  • pipenv run python3 -m unittest test2.py

最後に

flasgger で作成したアプリに対して unittest を適用してみました
Mock も使ってみましたが SwaggerView で定義した内容を Mock することで意図するテストを書くことができました

公式にテストの方法は書いてませんでしたが、Flask の test_client と標準の unittest を使っているので特に追加のモジュールなしでテストできるのは嬉しい点だと思います

0 件のコメント:

コメントを投稿