How to mock requests.Session.get using unittest module?

问题描述 投票:0回答:1

我想从

app.requests.Session.get
模拟
test_app.py
返回一个带有 404
requests.Response
的模拟
status_code
对象来生成一个
InvalidPlayerIdException
.

但是,从下面的输出中可以看出没有出现异常。是因为我使用了

with
从句,还是为什么不起作用?

参考:https://www.pythontutorial.net/python-unit-testing/python-mock-requests/

Output

(supersoccer-showdown) ➜  supersoccer-showdown-copy git:(main) ✗ python -m unittest                                                                                               git:(main|…3 
F
======================================================================
FAIL: test_pokemon_player_requestor_raise_exception (test_app.TestPlayerRequestor.test_pokemon_player_requestor_raise_exception)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/homebrew/Cellar/[email protected]/3.11.2_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/unittest/mock.py", line 1369, in patched
    return func(*newargs, **newkeywargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dkNiLyIv/supersoccer-showdown-copy/test_app.py", line 21, in test_pokemon_player_requestor_raise_exception
    self.assertRaises(InvalidPlayerIdException, requestor.getPlayerById, 1)
AssertionError: InvalidPlayerIdException not raised by getPlayerById

app.py

from __future__ import annotations
import abc
import requests

class InvalidPlayerIdException(Exception):
  pass

class Player(abc.ABC):
  def __init__(self, id: int, name: str, weight: float, height: float) -> None:
    self.id = id
    self.name = name
    self.weight = weight
    self.height = height

class PokemonPlayer(Player):
  def __init__(self, id: int, name: str, weight: float, height: float) -> None:
    super().__init__(id, name, weight, height)    

  def __repr__(self) -> str:
    return f'Pokemon(id={self.id},name={self.name},weight={self.weight},height={self.height})'

class PlayerRequestor(abc.ABC):
  def __init__(self, url: str) -> None:
    self.url = url

  @abc.abstractmethod
  def getPlayerCount(self) -> int:
    pass

  @abc.abstractmethod
  def getPlayerById(self, id: int) -> Player:
    pass

class PokemonPlayerRequestor(PlayerRequestor):
  def __init__(self, url: str) -> None:
    super().__init__(url)

  def getPlayerCount(self) -> int:
    with requests.Session() as rs:
      rs.mount('https://', requests.adapters.HTTPAdapter(
        max_retries=requests.urllib3.Retry(total=5, connect=5, read=5, backoff_factor=1)))
      with rs.get(f'{self.url}/api/v2/pokemon/', verify=True) as r:
        r.raise_for_status()
        json = r.json()
        return json["count"]

  def getPlayerById(self, id: int) -> Player:
    with requests.Session() as rs:
      rs.mount('https://', requests.adapters.HTTPAdapter(
        max_retries=requests.urllib3.Retry(total=5, connect=5, read=5, backoff_factor=1)))
      with rs.get(f'{self.url}/api/v2/pokemon/{id}', verify=True) as r:
        if r.status_code == 404:
          raise InvalidPlayerIdException
        r.raise_for_status()
        json = r.json()
        player = PokemonPlayer(id, json["name"], json["weight"], json["height"])
        return player

test_app.py

import unittest
from unittest.mock import MagicMock, patch
from app import *

class TestPlayerRequestor(unittest.TestCase):
  def setUp(self):
    pass

  def tearDown(self):
    pass

  @patch('app.requests')
  def test_pokemon_player_requestor_raise_exception(self, mock_requests):
    mock_response = MagicMock()
    mock_response.status_code = 404
    mock_session = MagicMock()
    mock_requests.Session = mock_session
    instance = mock_session.return_value
    instance.get.return_value = mock_response
    requestor = PokemonPlayerRequestor('https://pokeapi.co')
    self.assertRaises(InvalidPlayerIdException, requestor.getPlayerById, 1)
python unit-testing testing python-requests python-unittest
1个回答
1
投票

你走在正确的轨道上,上下文管理器确实会干扰你的测试,因为你的代码正在调用

__enter__
dunder 方法,只有一次,但是两次!

如果你陷入模拟地狱,它有助于打印你的模拟来调试它。

这是我打印出来的结果:

<MagicMock name='requests.Session().__enter__().get().__enter__()' id='4357377616'>

然后我将您的测试重写为:

  @patch('app.requests')
  def test_pokemon_player_requestor_raise_exception(self, mock_requests):
    mock_session = MagicMock()
    mock_requests.Session = mock_session

    session_instance = MagicMock()
    mock_session().__enter__.return_value = session_instance

    mock_response = MagicMock()
    mock_response.status_code = 404

    session_instance.get().__enter__.return_value = mock_response

    requestor = PokemonPlayerRequestor('https://pokeapi.co')
    self.assertRaises(InvalidPlayerIdException, requestor.getPlayerById, 1)
➜  stackoverflow python -m unittest
<MagicMock name='requests.Session().__enter__()' id='4357333536'>
<MagicMock name='requests.Session().__enter__().get().__enter__()' id='4357377616'>
.
----------------------------------------------------------------------
Ran 1 test in 0.003s

OK

希望对你有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.