[python 3]mockの1セット勝負-2
第1部長編物語の最後に
お願いだgetメソッドにパッチを適用し、
でも私たちは、
1.
2.
応答を返す
1番はあまり難しくありません.
Custom Response
したがって、少なくとも2つの機能を有する
この
実際の応答として返す
残念なことに、contentというprotectedプロパティに直接アクセスする必要があります.
複数の応答を返す
しかし、すべての
もちろん四半期によって例外もたくさんあります.
これらのブランチと例外処理のすべてをテストコードで上書きするには、次の手順に従います.
場合によっては多様な
この時は私が使う機能もあります
side_effect
Mockの
作成した
正式な書類は、
簡単なサンプルコードを次に示します.
サンプルコード
複数url
テストされたコードとテストコードをよく見てください.
外部apiサーバにリクエストを送信中にエラーが発生したと仮定した場合は、次のコードも実行できます.
ここでは
の最後の部分
長い文章を書くのは初めてです.力が抜けた...こんなに長く書くつもりはなかったのに、なぜかたくさん書いてしまった.
私が経験した過程を書く文章だったが、下品なコードを主とする文章になった.ガチャガチャ音を立てる
実はmockを応用する時に多くの悩みがあります
すべてのtestメソッドは、それぞれのside effectに割り当てられた関数を作成する必要がありますか?
1つのAPIモジュールにおいて、
このような悩みがあるのは、私が作成したAPIモジュールが1つのリクエストを処理するときに、少なくとも2、3回外部APIサーバにリクエストを送信するからです...
従って
sidefectに直接異常発生コードを追加しますか?それとも私が作成した関数にブランチに基づいて異常を発生しますか?
mockをテストコードに最善の方法で適用しましたが、まだ満足できません.テストコードが簡潔ではないからですか?
それとも私が作ったAPIが最初からあまりよくなかったからですか?
いろいろな悩みを頭の後ろに置いて、先に書いて、それからこのように書きました.
この文章を読んでいる他の人に少し役に立つと、満足します.
ここまでです.
お願いだgetメソッドにパッチを適用し、
'blah blah'
という文字列を返します.でも私たちは、
1.
Response
個のオブジェクトを返したい!2.
get
とpost
のurl
またはheader
により、多種多様なResponse
を返却したい!応答を返す
1番はあまり難しくありません.
Response
対象を作ればいい!どうしよう.Custom Response
class Response:
def __init__(self, **kwargs):
self.status_code = kwargs['status']
self.data = kwargs['data']
def json(self):
return self.data
res_data = {
'message': 'hello, response',
}
res = Response(status=200, data=res_data)
res.status_code
> 200
res_json = res.json()
res_json['message']
> 'hello, response'
筆者はすべてのResponse
においてstatus_code
,json()
語樹状図のみを用いた.したがって、少なくとも2つの機能を有する
Custom Response
オブジェクトが生成される.この
Custom Response
を直接適用しましょう!# test.py
from unittest import mock
from rest_framework.test import APITestCase
class Response:
def __init__(self, **kwargs):
self.status_code = kwargs['status']
self.data = kwargs['data']
def json(self):
return self.data
@mock.patch("hello_world.requests.get")
class TestAPIHello(APITestCase):
def setUp(self):
self.user = get_user()
do_stuff()
def testcase_00_hello_world(self, mock_get):
mock_get.return_value = Response(
status=200,
data={'user': 'Lee'}
)
response = self.client.get(url="/api/hello-world/")
self.assertEqual(response.status_code, 200)
こつこつ!実際の応答として返す
requests
モジュールのResponse
を返却したい場合は、次のようにできます.# test.py
import requests
from unittest import mock
from rest_framework.test import APITestCase
@mock.patch("hello_world.requests.get")
class TestAPIHello(APITestCase):
def setUp(self):
self.user = get_user()
do_stuff()
def testcase_00_hello_world(self, mock_get):
my_response = requests.models.Response()
response.status_code = 200
response_content = json.dumps({'user': 'Lee'})
response._content = str.encode(response_content)
mock_get.return_value = my_response
response = self.client.get(url="/api/hello-world/")
self.assertEqual(response.status_code, 200)
testcase_00_hello_world
手法では,Response
モデルを実際に用いた.残念なことに、contentというprotectedプロパティに直接アクセスする必要があります.
複数の応答を返す
しかし、すべての
requests.get()
メソッドが同じResponse
を送信することは望ましくない.もちろん四半期によって例外もたくさんあります.
これらのブランチと例外処理のすべてをテストコードで上書きするには、次の手順に従います.
場合によっては多様な
Response
が発生するはずです!この時は私が使う機能もあります
side_effect
Mockの
side_effect
は、シミュレーション例において예외
の異常を発生させることを可能にする.作成した
함수
をmockインスタンスに適用できます.正式な書類は、
side_effect
を使用する様々な方法を説明する.簡単なサンプルコードを次に示します.
from unittest import mock
def hello_world(name):
return f'Hello, world and {name}'
m = mock.Mock()
m.side_effect = hello_world
m('Lee !!')
> Hello, world and Lee !!
行け!サンプルコード
複数url
テストされたコードとテストコードをよく見てください.
# hello_world.py
import requests
from rest_framework.views import APIView
from rest_framework.response import Response
class HelloView(APIView):
def get(self, request):
res1 = requests.get(url='https://some.com/api/user-info/')
# Send one more request !!
res2 = requests.get(url='https://some.com/api/org-info/')
if res1.status_code == res2.status_code == 200:
res1_json = res1.json()
res2_json = res2.json()
data = {
"message": "Hello, World!",
"user": res1_json["user"],
"org": rest2_json["org"],
}
return Response(data, status=200)
data = {
"message": "Error!",
"user": "No user",
}
return Response(data, status=503)
2つのurlにrequestが送信されます.# test.py
import requests
from unittest import mock
from rest_framework.test import APITestCase
def mock_request_get(**kwargs):
response = requests.models.Response()
response.status_code = 200
url = kwargs.get('url')
if url == 'https://some.com/api/user-info/':
response_content = json.dumps({'user': 'Lee'})
response._content = str.encode(response_content)
elif url == 'https://some.com/api/org-info/':
response_content = json.dumps({'org': 'Avengers'})
response._content = str.encode(response_content)
else:
response.status_code = 400
return response
@mock.patch("hello_world.requests.get")
class TestAPIHello(APITestCase):
def setUp(self):
self.user = get_user()
do_stuff()
def testcase_00_hello_world(self, mock_get):
mock_get.side_effect = mock_request_get
response = self.client.get(url="/api/hello-world/")
self.assertEqual(response.status_code, 200)
異常が発生する外部apiサーバにリクエストを送信中にエラーが発生したと仮定した場合は、次のコードも実行できます.
# hello_world.py
import requests
from rest_framework.views import APIView
from rest_framework.response import Response
class HelloView(APIView):
def get(self, request):
try:
res1 = requests.get(url='https://some.com/api/user-info/')
res2 = requests.get(url='https://some.com/api/org-info/')
# Return response with status code 500
# if OSError raises.
except OSError:
return Response(status=500)
if res1.status_code == res2.status_code == 200:
res1_json = res1.json()
res2_json = res2.json()
data = {
"message": "Hello, World!",
"user": res1_json["user"],
"org": rest2_json["org"],
}
return Response(data, status=200)
data = {
"message": "Error!",
"user": "No user",
}
return Response(data, status=503)
hello_world.py
からrequests
と書かれた部分にエラーハンドルコードが追加されました.# test.py
import requests
from unittest import mock
from rest_framework.test import APITestCase
def mock_request_get(**kwargs):
response = requests.models.Response()
response.status_code = 200
url = kwargs.get('url')
if url == 'https://some.com/api/user-info/':
response_content = json.dumps({'user': 'Lee'})
response._content = str.encode(response_content)
elif url == 'https://some.com/api/org-info/':
response_content = json.dumps({'org': 'Avengers'})
response._content = str.encode(response_content)
else:
response.status_code = 400
return response
@mock.patch("hello_world.requests.get")
class TestAPIHello(APITestCase):
def setUp(self):
self.user = get_user()
do_stuff()
def testcase_00_hello_world(self, mock_get):
mock_get.side_effect = mock_request_get
response = self.client.get(url="/api/hello-world/")
self.assertEqual(response.status_code, 200)
def testcase_01_external_api_error(self, mock_get):
mock_get.side_effect = OSError()
response = self.client.get(url="/api/hello-world/")
self.assertEqual(response.status_code, 500)
testcase_01_external_api_error
試験方法を追加した.ここでは
side_effect
に関数を割り当てるのではなく,直接例外を割り当てる.の最後の部分
長い文章を書くのは初めてです.力が抜けた...こんなに長く書くつもりはなかったのに、なぜかたくさん書いてしまった.
私が経験した過程を書く文章だったが、下品なコードを主とする文章になった.ガチャガチャ音を立てる
実はmockを応用する時に多くの悩みがあります
すべてのtestメソッドは、それぞれのside effectに割り当てられた関数を作成する必要がありますか?
1つのAPIモジュールにおいて、
requests
に書き込まれたすべての部分は、side_effect
に割り当てられた関数を配布することによって簡略化する必要があるかどうか.このような悩みがあるのは、私が作成したAPIモジュールが1つのリクエストを処理するときに、少なくとも2、3回外部APIサーバにリクエストを送信するからです...
従って
side_effect
関数からurlによって異なる処理のための分岐ゲート地獄sidefectに直接異常発生コードを追加しますか?それとも私が作成した関数にブランチに基づいて異常を発生しますか?
mockをテストコードに最善の方法で適用しましたが、まだ満足できません.テストコードが簡潔ではないからですか?
それとも私が作ったAPIが最初からあまりよくなかったからですか?
いろいろな悩みを頭の後ろに置いて、先に書いて、それからこのように書きました.
この文章を読んでいる他の人に少し役に立つと、満足します.
ここまでです.
Reference
この問題について([python 3]mockの1セット勝負-2), 我々は、より多くの情報をここで見つけました https://velog.io/@fregataa/Python-mock과의-한판-승부-2テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol