Reputation: 909
I'm having a real hard time understanding how to mock a class that has a property and setter fixtures that access a "private" attribute.
import pytest
from pytest_mock import MockFixture
from unittest.mock import MagicMock
from typing import List
class MyEntity:
_my_list: List[str] = []
def __init__(self, list_vals = []):
self._my_list = list_vals
@property
def my_list(self) -> List[str]:
return self._my_list
@my_list.setter
def my_list(self, value: List[str]):
self._my_list = value
def append(self, value: str):
self._my_list.append(value)
class Foo:
def generate_entity(self, list_vals: List[str]) -> MyEntity:
return MyEntity()
def set_values(self, entity: MyEntity, list_vals: List[str]) -> MyEntity:
entity.my_list = list_vals
return entity
def add_value(self, entity: MyEntity, value: str) -> MyEntity:
entity.append(value)
return entity
@pytest.fixture
def mock_my_entity(mocker: MockFixture) -> MagicMock:
namespace = f"{__name__}.{MyEntity.__name__}"
mock_my_entity = mocker.patch(namespace, autospec=True)
return mock_my_entity.return_value
def test_foo(mock_my_entity):
expect_list_values = ["Hello", "World"]
foo = Foo()
entity = foo.generate_entity(expect_list_values)
assert len(entity._my_list) == 0
entity = foo.set_values(entity, expect_list_values)
assert entity._my_list == expect_list_values
expected_extra_value = "more"
entity = foo.add_value(entity, expected_extra_value)
assert entity._my_list == expect_list_values + expected_extra_value
After running the test, this is what I get:
mock_my_entity = <NonCallableMagicMock name='MyEntity()' spec='MyEntity' id='4351847632'>
def test_foo(mock_my_entity):
expect_list_values = ["Hello", "World"]
foo = Foo()
entity = foo.generate_entity(expect_list_values)
assert len(entity._my_list) == 0
entity = foo.set_values(entity, expect_list_values)
> assert entity._my_list == expect_list_values
E AssertionError: assert <MagicMock na...='4362862544'> == ['Hello', 'World']
E Right contains 2 more items, first extra item: 'Hello'
E Full diff:
E - <MagicMock name='MyEntity()._my_list' spec='list' id='4362862544'>
E + ['Hello', 'World']
scratchpad.py:58: AssertionError
I've also tried using PropertyMock
in various ways, but nothing seems to work.
How do I get this to work. How do I mock the MyEntity
class so that everything works the way it should?
Upvotes: 1
Views: 1914
Reputation: 16855
I'm still not sure I understand what you want to do, but I'll propose a possibility that could fix the test as shown here, comments inline.
def test_foo(mock_my_entity):
def append(value):
mock_my_entity.my_list.append(value)
expect_list_values = ["Hello", "World"]
foo = Foo()
# for `append` in the mock to behave as in the original class,
# we have to change it
mock_my_entity.append = append
entity = foo.generate_entity(expect_list_values)
assert len(entity.my_list) == 0
# in this case, the list is directly passed to your class,
# so I prevent that it will change with changes in the class by copying it
# in reality, this will probably be done in MyEntity
entity = foo.set_values(entity, expect_list_values.copy())
# I changed this and further checks to check for the property
# instead of the attribute, as this has the same semantics
assert entity.my_list == expect_list_values
expected_extra_value = "more"
entity = foo.add_value(entity, expected_extra_value)
assert entity.my_list == expect_list_values + [expected_extra_value]
This will work, but I think this is not what you really need. Just wouldn't fit into the comments...
Upvotes: 1