Help us understand the problem. What is going on with this article?

Pythonのmockについての備忘録

先日PythonのMockに悩まされまくったので備忘録を置いておきます。

とりあえず公式ドキュメント

unittest.mock --- モックオブジェクトライブラリ
unittest.mock --- 入門

2時間ぐらい悩んだことが公式にさらっと書いてあった。
公式は偉大

requests.getをmockする

tori01.py
import requests

def get_qiita(url):
    response = requests.get(url)
    return response

urlでgetして返ってきたresponseを返すだけ

test_tori01.py
import unittest
from mock import Mock, patch

import tori01

class TestTori01(unittest.TestCase):

    @patch("tori01.requests.get")
    def test_get_response(self, requests_get):
        requests_get.return_value.status_code = 200

        res = tori01.get_response("mock.url")
        self.assertEqual(res.status_code, 200)

ステータスコードでアサーションチェック
今回これらのコードを土台とする

patch周り

tori01.pyrequestsがimportされているので
@patch("tori01.requests.get")でpatchされる

これがtori01.pyrequests.getがimportされていると
@patch("tori01.get")としないとpatchされない

tori01.py
# import requests から変更
from requests import get

def get_response(url):
    response = get(url)
    return response
test_tori01.py
import unittest
from mock import Mock, patch

import tori01

class TestTori01(unittest.TestCase):

    # @patch("tori01.requests.get") から変更
    @patch("tori01.get")
    def test_get_response(self, requests_get):
        requests_get.return_value.status_code = 200

        res = tori01.get_response("mock.url")
        self.assertEqual(res.status_code, 200)



requests.getではなく、requestsをmockしたい場合(どっちが正統なんだろうか)

test_tori01.py
import unittest
from mock import Mock, patch

import tori01

class TestTori01(unittest.TestCase):

    # @patch("tori01.requests.get") から変更
    # 引数の命名もrequests.get→requestsに変更
    @patch("tori01.requests")
    def test_get_response(self, requests):
        # requests_get.return_value.status_code = 200 から変更
        requests.get.return_value.status_code = 200

        res = tori01.get_response("mock.url")
        self.assertEqual(res.status_code, 200)

関数を呼び出す

呼び出された時の引数を確認することができる。

test_tori01.py
import unittest
from mock import Mock, patch

import tori01

class TestTori01(unittest.TestCase):

    @patch("tori01.requests.get")
    def test_get_response(self, requests_get):

        # mockを返す関数を作り、呼び出されるようにする。
        def requests_get_mock(url):
            return Mock(status_code = 200, url = url)

        requests_get.side_effect = requests_get_mock

        res = tori01.get_response("mock.url")
        self.assertEqual(res.status_code, 200)
        self.assertEqual(res.url, "mock.url")



こんな回りくどいことをしなくてもassert_called_withでチェックできる。
他のassert系も色々ある

test_tori01.py
import unittest
from mock import Mock, patch

import tori01

class TestTori01(unittest.TestCase):

    @patch("tori01.requests.get")
    def test_get_response(self, requests_get):
        requests_get.return_value.status_code = 200

        res = tori01.get_response("mock.url")
        self.assertEqual(res.status_code, 200)
        requests_get.assert_called_with("mock.url") #追加



引数によって戻り値を変化

test_tori01.py
import unittest
from mock import Mock, patch

import tori01

class TestTori01(unittest.TestCase):

    @patch("tori01.requests.get")
    def test_get_response(self, requests_get):

        vals = {"mock.url":200, "error_mock.url":404}
        def requests_get_mock(val):
            return Mock(status_code = vals[val])

        requests_get.side_effect = requests_get_mock

        res = tori01.get_response("mock.url")
        res_error = tori01.get_response("error_mock.url")
        self.assertEqual(res.status_code, 200)
        self.assertEqual(res_error.status_code, 404)



例外を投げることもできる

test_tori01.py
import unittest
import requests
from mock import Mock, patch

import tori01

class TestTori01(unittest.TestCase):

    @patch("tori01.requests.get")
    def test_get_response(self, requests_get):

        # side_effectに例外クラスを設定すれば例外が投げられる
        requests_get.side_effect = requests.HTTPError

        with self.assertRaises(requests.HTTPError):
            tori01.get_response("mock.url")

追記したり、その2を書くかも

MagicMockとか…

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした