Как имитировать метод только для чтения с помощью pytest-mock ⇐ Python

Программы на Python
Anonymous
Как имитировать метод только для чтения с помощью pytest-mock

Сообщение Anonymous »

Я хочу протестировать свои реализации клиента и сервера, которые используют сокет для связи. Поэтому я попытался использовать pytest-mock, чтобы заменить методы recv и sendall сокета, чтобы не приходилось иметь дело с установкой реального соединения.
Я придумал этот код:

Код: Выделить всё

from collections import deque
from threading import Lock
import socket
from time import sleep
from typing import Deque

import pytest
from pytest_mock import MockFixture

from comms import Comms

def mocked_socket(mocker: MockFixture):
connection = socket.socket()
backing_store: Deque[int] = deque()
lock = Lock()

def receiver(n: int):
with lock:
# NOTE: To better simulate socket behaviour, we allow the sender to refill the backing store for the duration of connection.timeout.
bl = len(backing_store)
if bl == 0 and connection.timeout is not None:
lock.release()
sleep(connection.timeout)
lock.acquire()

# FIXME: We raise a timeout here, even if connection.timeout is None (i.e. socket is blocking). This is, because returning an empty bytes object is interpreted as the other side having terminated the connection. If we wanted to model socket even more closely, we should have a condition variable for reception, that this thread can wait on.
bl = len(backing_store)
if bl == 0:
raise socket.timeout

n_cap = min(len(backing_store), n)
return bytes(backing_store.popleft() for _ in range(n_cap))

def sender(buffer: bytes):
with lock:
backing_store.extend(buffer)

mocker.patch.object(connection, "recv", wraps=receiver)
mocker.patch.object(connection, "sendall", wraps=sender)

return connection

def test(mocker: MockFixture):
connection = mocked_socket(mocker)
server = Comms(connection)
client = Comms(connection)

# ... whatever I want to test
Однако, когда я пытаюсь запустить pytest, я получаю кучу следующих ошибок:

Код: Выделить всё

        self.temp_original = original
self.is_local = local
self._exit_stack = contextlib.ExitStack()
try:
>           setattr(self.target, self.attribute, new_attr)
E           AttributeError: 'socket' object attribute 'recv' is read-only

/usr/lib/python3.12/unittest/mock.py:1567: AttributeError
Похоже, то, что я пытаюсь сделать, невозможно, потому что исправление Recv/ требует удаления их исходных реализаций, что не работает, поскольку они помечены как доступные только для чтения.
Я нашел Как имитировать свойство только для чтения с помощью макета?, но это только имеет дело с насмешливыми свойствами, а не методами.
Я никогда раньше не использовал pytest, unittest.mock и т. д., так есть ли простое решение, которое мне не хватает? Является ли то, что я пытаюсь сделать, правильным подходом?
Спасибо за вашу помощь.

Подробнее здесь: https://stackoverflow.com/questions/790 ... ytest-mock

Вернуться в «Python»