I am trying to mock a method of an instance that is being used and impeded into another class. This is in order to test the class independent of that method.
This is the class and the function that needs to be mocked is redis_client.fields_allowed:
#app.auth.roles.py
from app.redis.client import redis_client
role_count = 0
@dataclass
class Role:
id: int
name: str
byte: int
@staticmethod
def new(name: str, *roles: Role) -> Role:
global role_count
role_count += 1
byte: int = 1 << role_count
for role in roles:
byte |= role.byte
return Role(id=role_count, name=name, byte=byte)
def __or__(self, other: Union[Role, int]) -> int:
if isinstance(other, Role):
return self.byte | other.byte
return self.byte | other
def __and__(self, other: Union[Role, int]) -> int:
if isinstance(other, Role):
return self.byte & other.byte
return self.byte & other
def fields(self, *field_ids: int) -> Callable[[int], Role]:
def func(user_id: int) -> Role:
#to be mocked
if redis_client.fields_allowed(user_id, self.id, list(field_ids)):
return self
return Role(id=0, name="None", byte=0)
return func
This is my test (access_token fixture created before):
#app.auth.test_auth.py
@patch.object(roles.Role, "fields.func.redis_client.fields_allowed")
def test_field_ownership(access_token, fields_allowed):
fields_allowed.return_value = True
access_token_str = access_token
#etc
The test gives fixture 'fields_allowed' not found. How can I mock it? without rewriting the class and using dependency injection with object redis_client and class Role.
Update.
It looks like the patched function needs to come before the fixture:
@patch("app.auth.roles.redis_client.fields_allowed")
def test_valid_field_ownership(fields_allowed, access_token):
fields_allowed.return_value = True
access_token_str = access_token
Now it looks like it is patched. However it does not seem to return True when called. see below
#method in Role class
#...
def fields(self, *field_ids: int) -> Callable[[int], Role]:
def func(user_id: int) -> Role:
if v := redis_client.fields_allowed(user_id, self.id, list(field_ids)):
print(v) #prints <coroutine object AsyncMockMixin._execute_mock_call at 0x7f8cb7e5e340>
return self
else:
raise error.NotEnoughClaims(
status_code=401, message="Not enough claims"
)
return func
The return looks like an instance of the patch <coroutine object AsyncMockMixin._execute_mock_call at 0x7f8cb7e5e340> instead of True. Why is this happening?
Update.
I found the issue. redis_client.fields_allowed is awaitable. Therefore I needed to make some fns async and also I needed to use pytest-asyncio plugin for the tests to use async fns.
source https://stackoverflow.com/questions/74363748/how-to-mock-a-function-inside-a-class-method
Comments
Post a Comment