Так что я довольно новичок с pytest
и mock
, но все еще имею опыт работы с junit
и с насмешками mockito
для groovy
(который поставляется с удобной функцией when(...).thenAnswer/Return
)
Я написал простой класс для разбора и записи xml файлов. Единственная цель этого класса для существования - это насмешка, чтобы провести модульное тестирование плагина, над которым я сейчас работаю. Этот личный проект также используется в качестве учебного пособия, помогающего мне в выполнении моих рабочих обязанностей (на основе devOps python)
Очевидно, мне тоже нужно было его протестировать.
Вот класс:
from lxml import etree
from organizer.tools.exception_tools import ExceptionPrinter
class XmlFilesOperations(object):
@staticmethod
def write(document_to_write, target):
document_to_write.write(target, pretty_print=True)
@staticmethod
def parse(file_to_parse):
parser = etree.XMLParser(remove_blank_text=True)
try:
return etree.parse(file_to_parse, parser)
except Exception as something_happened:
ExceptionPrinter.print_exception(something_happened)
А вот и модульный тест для него:
import mock
from organizer.tools.xml_files_operations import XmlFilesOperations
FILE_NAME = "toto.xml"
@mock.patch('organizer.tools.xml_files_operations.etree.ElementTree')
def test_write(mock_document):
XmlFilesOperations.write(mock_document, FILE_NAME)
mock_document.write.assert_called_with(FILE_NAME, pretty_print=True)
@mock.patch('organizer.tools.xml_files_operations.etree')
def test_parse(mock_xml):
XmlFilesOperations.parse(FILE_NAME)
mock_xml.parse.assert_called()
Также вот pip-файл, используемый для этой python среды:
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
lxml = "*"
pytest = "*"
pytest-lazy-fixture = "*"
mock = "*"
MKLpy = "*"
Я хотел бы улучшить этот тест, используя функцию assert_called_with
в функции test_parse
. Однако, чтобы это работало, мне нужно получить точный синтаксический анализатор, который используется в методе XmlFilesOperations.parse
, так что я представлял себе и его издевательство. Для этого мне нужен вызов etree.XMLParser(remove_blank_text=True)
, чтобы вернуть макет объекта
Вот что я пытался:
import mock
import pytest
from lxml import etree
from organizer.tools.xml_files_operations import XmlFilesOperations
FILE_NAME = "toto.xml"
@pytest.fixture()
def mock_parser():
parser = mock.patch('organizer.tools.xml_files_operations.etree.XMLParser').start()
with mock.patch('organizer.tools.xml_files_operations.etree.XMLParser', return_value=parser):
yield parser
parser.stop()
@mock.patch('organizer.tools.xml_files_operations.etree')
def test_parse(mock_xml, mock_parser):
XmlFilesOperations.parse(FILE_NAME)
mock_xml.parse.assert_called_with(FILE_NAME, mock_parser)
Я получаю следующую ошибку:
def raise_from(value, from_value):
> raise value
E AssertionError: expected call not found.
E Expected: parse('toto.xml', <MagicMock name='XMLParser' id='65803280'>)
E Actual: parse('toto.xml', <MagicMock name='etree.XMLParser()' id='66022384'>)
Таким образом, смоделированный объект, возвращаемый вызовом, не является тем же смоделированным объектом, который я создал.
С Mockito я бы сделал что-то вроде этого:
parser = etree.XmlParser()
when(etree.XMLParser(any()).thenReturn(parser)
И это сработало бы. Как я могу это исправить?