python - 如何对实例化的模拟类对象进行断言

标签 python python-3.x python-mock

在我的测试类的构造函数中,套接字对象被实例化并分配给类成员。我模拟了套接字类并将模拟的套接字对象设置为套接字构造函数调用的返回值。然后我想断言在该对象上调用 connect() 和 sendall() 。当我对原始模拟类对象或我设置为在构造函数调用中返回的对象进行断言时,我总是收到断言错误,表明未调用函数。

我知道我不能模拟正在测试的类(及其成员),因为这会违背这里的目的。

伪代码:

import socket

Class socketHandler():
    def __init__(...):
    self.mySocket = socket(...)
    ...
    self.mySocket.connect(...)

    def write(message):
        self.mySocket.sendall(message)

测试:

from unittest import mock
from unittest.mock import MagicMock #not sure if i need this
import pytest
import socketHandler

@mock.patch(socketHandler.socket)
def test_socket_handler(mockSocket):
    ...
    new_sock = mock_socket()
    mock_socket.return_value = new_sock

    mySocketHandler = SocketHandler(...)

    mock_socket.socket.assert_called_with(...)
    new_sock.connect.assert_called_with(...) #fails (never called)
    mock_socket.connect.assert_called_with(...) #fails (never called)
    #likewise for the sendall() method call when mysocketHandler.write(..)
    #is called

本次测试的目的是:

  1. 确保使用正确的参数调用套接字库的构造函数。

  2. 确保使用正确的参数调用 connect()。

  3. 当我将消息传递到 mySocketHandler.write() 方法时,确保以我希望的方式调用 sendall()。

最佳答案

完整的答案源自@ryanh119和这篇文章给出的提示link

我将修复 ryanh119 上面给出的示例,并避免编辑我弄乱的原始问题,因此为了完整性:

from unittest import mock
import pytest
import socketHandler

@mock.patch("app_directory.socketHandler.socket")
def test_socket_handler(mockSocketClass):

# mockSocketClass is already a mock, so we can call production right away.
mySocketHandler = SocketHandler(...)

# Constructor of mockSocketClass was called, since the class was imported
#like: import socket we need to:
mockSocketClass.socket.assert_called_with(...)

# Production called connect on the class instance variable
# which is a mock so we can check it directly.
# so lets just access the instance variable sock
mySocketHandler.mySocket.connect.assert_called_with(...)

# The same goes for the sendall call:
mySocketHandler.mySocket.sendall.assert_called_with(expectedMessage)

我还做了一些研究,我想提一下另外两个解决方案。它们并不像上面的那样正确,但它是:

  1. 通过更改 socketHandler 的 __init__ 来使用依赖注入(inject)来接收套接字对象,并且仅在参数中未提供时才实例化它。这样我就可以传入一个模拟或 MagicMock 对象并使用它来进行断言。
  2. 利用名为 MonkeyPatch 的极其强大的模拟/修补工具它实际上可以修补/模拟类的实例变量。这种方法就像试图用火箭发射器杀死苍蝇一样。

关于python - 如何对实例化的模拟类对象进行断言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46569317/

相关文章:

python - 动态创建 lambda 函数列表,其中每个下一个函数都使用前一个函数

string - Python3 TypeError : list indices must be integers or slices, 不是 str

python - 模拟具有特定返回值的实例方法?

python - 提供节点名或服务名,或未知

python - 使用 Python 读取 Azure ADLS Gen2 文件(不带 ADB)

python - 在 apply 中向量化一个非常简单的 pandas lambda 函数

python - 加快随机加权选择的速度,而无需在python中进行替换

python-3.x - 否定 np.where 中的 np.isnan

Python 如何重用 Mock 以避免多次编写 mock.patch?

python - mock.patch 忽略完全导入的函数的原因是什么?