Hi Ethan,
You have the right idea with mocking the decorator. In order for it to work, you could use monkeypatch to override the decorator with its mock and use importlib.reload to ensure that the changes are reflected (module caching appears to be the reason for which your mock isn't applying as expected.
E.g
You have a function that substracts 2 from a provided value, and a decorator defined in mydecorator.py that adds 4 to the value:
from mydecorator import add_four_decorator
@add_four_decorator
def subtract(a):
return a - 2
Mocking add_four_decorator in the unit test would look like the following:
import calculator
def do_nothing(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
def test_calculator_subtract(monkeypatch):
monkeypatch.setattr('mydecorator.add_four_decorator', do_nothing)
import importlib
importlib.reload(calculator)
res = calculator.subtract(12)
assert res == 10
Above we are grabbing the monkeypatch fixture and using monkeypatch.setattr to pass in the <file_path>.<function_name> of the decorator, and the decorator to replace it with as the second parameter. We are then using importlib.relead to import the module again (rather than using the cached file) to ensure the mock is applied.
The same idea would apply with ajax here and your test_func_to_be_tested would contain something like this:
from q2_sdk.core import web
async def test_func_to_be_tested(mock_success_class):
...
monkeypatch.setattr('q2_sdk.core.web.ajax', mock_decorator)
import importlib
importlib.reload(web)
actual = await handler.func_to_be_tested()
assert isinstance(actual, type(mock_success))
@<1455287096196468736|Solene Sossah> Hi, Solene. Thank you for the idea of reloading the module. In the last example that you gave, you wrote that calculator is the module that should be reloaded. In the context of a unit test for the SDK extension, which module is it that actually needs to be reloaded? When I attempt to do it on "extension", it only clears out all of my other patches.
— Ethan Pittman 2 years agoHi Ethan, sorry there was a typo in the provided code. I believe you would want to reload the file that contains ajax (web.py in this case from q2_sdk.core). I have updated the example in my previous response
— Solene Sossah 2 years ago@<1455287096196468736|Solene Sossah> For some reason, this is still having no effect. It is as though the decorator is not being patched at all. For testing purposes, it may be the most reliable thing at this point to just let the decorator run and ensure that returning a TectonResponse object returns the expected output. It's not ideal and really isn't a unit test, but it still provides some degree of test coverage.
— Ethan Pittman 2 years ago