-
-
Notifications
You must be signed in to change notification settings - Fork 141
-
-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
xxx() missing 1 required positional argument: 'mocker' #174
Comments
Please try to inherit your test class from "object" instead. (see the code in https://docs.pytest.org/en/latest/fixture.html#autouse-fixtures-xunit-setup-on-steroids) |
The problem with inheriting from |
pytest fixtures cannot be used in One workaround is to use an autouse fixture (which work un class KeysModuleTests(TestCase):
@pytest.fixture(autouse=True)
def __inject_fixtures(self, mocker):
self.mocker = mocker
def test_calls_operation(self):
keys = mnt.keys.end()
self.mocker.spy(keys, 'op_end')
# ... Closing for now but feel free to follow up with further questions. |
Thank you for the explanation and workaround, that helps me get going. I've create an issue with the VSC python plugin to support discovery of non-Testcase derived test classes. |
Just in case others find this issue, I've wrapped your workaround slightly differently in a simple fixture, so I can either use it on a class or a single method using @pytest.fixture(scope='function')
def mocka(request, mocker):
"""Exposes pytest-mock's "mocker" as "self.mocker" in
unittest.TestCase-based tests.
"""
request.instance.mocker = mocker Thank you again for setting me on the right track! |
Glad you could get going. Btw, didn't you forget to pass |
Actually, no. Because I have a larger set of tests and only enable three fixture on some sets by explicitly specifying it. |
I thought your test suite was |
Hi @alterEgo123, That's because each test method in your class is executed with a new class TestPlace(AsyncHTTPTestCase):
@pytest.fixture(autouse=True, scope='function')
def mocka(self):
TestPlace.shared = 0
def test_login(self):
response = self.fetch('/places/login', method='POST',
headers=None,
body=json_encode({
'email': email,
'password': 'verystrongpassword'
}),
)
TestPlace.shared = ast.literal_eval(response.body.decode('ascii'))['token'] Full disclosure, tests should not independent from one another, meaning that a test should not depend on another test being run first. Otherwise you will be creating coupling between your tests, which is not healthy/recommended. |
Thanks a lot ! |
It really depends on the case, but if you have two behaviors that are tightly coupled (login and then check a token) it is probably better to do both checks into the same test method. |
I need to test functionalities like resetting a password, listing Users as an admin, managing roles, etc. All of these rely on a JWT token in the headers. Should I rewrite the login and token extracting code in all of these tests ? |
Ahh I see. No, what is usually done is to move that logic to its own fixture, then you can reuse it as appropriate: class TestPlace(AsyncHTTPTestCase):
@pytest.fixture
def admin(self):
response = self.fetch(...
body=json_encode({
'email': "admin@example.com",
'password': 'verystrongpassword'
}),
)
token = ast.literal_eval(response.body.decode('ascii'))['token']
...
return User(token)
def test_admin_access(self, admin_user):
assert can_delete_project(admin_user) Something like that. Fixtures are a great way to share common "setup" code between tests. |
It returns missing 1 required positional argument 😔 |
Hi, I am receiving "AttributeError: 'GbtEst_Test' object has no attribute 'mocker'" when trying to use the above example, I wondered if anyone could help please! Thanks in advance Class attempting to test from sklearn.ensemble import GradientBoostingClassifier
from typing import Callable
import numpy as np
class BehavEst:
def __init__(self, estimator:Callable) -> None:
self.estimator = estimator
def eval_pdf(self, indep_vals, dep_vals):
raise NotImplementedError
class GbtEst(BehavEst):
def __init__(self, estimator:GradientBoostingClassifier) -> None:
super().__init__(estimator=estimator)
def eval_pdf(self, indep_vals:np.array, dep_vals:np.array):
slct_msk = (np.array(range(0,len(indep_vals))), dep_vals)
probs = self.estimator.predict_proba(X=indep_vals)
return probs[slct_msk] Test file import unittest
import pytest
import numpy as np
@pytest.fixture(scope='function', autouse=True)
def mocka(obj, mocker):
"""Exposes pytest-mock's "mocker" as "self.mocker" in
unittest.TestCase-based tests.
"""
obj.instance.mocker = mocker
behav_est = GbtEst(estimator=GradientBoostingClassifier())
class GbtEst_Test(unittest.TestCase):
@pytest.mark.usefixtures('mocka')
def test_1_eval_pdf(self):
# Dependant values range between 1 and 5
num_features = 10
# correct_pred = [
# True, False, False, True, False, True, True
# ]
dep_vals_input = np.array([1,2,1,5,2,4,1])
indep_vals_input = np.arange(0,len(dep_vals_input)*num_features)
indep_vals_input = indep_vals_input.reshape(-1,num_features)
np.random.seed(seed=1)
mocked_value = np.random.uniform(
0,1,len(dep_vals_input)*dep_vals_input.max()).reshape(
len(dep_vals_input), dep_vals_input.max())
actual_res = []
for idx, vals in zip(dep_vals_input, mocked_value):
actual_res.append(vals[idx-1])
actual_res = np.array(actual_res)
dep_vals_input=dep_vals_input.reshape(-1,1)
estimator_mock = self.mocker.patch("behav_est.estimator.predict_proba")
estimator_mock.return_value = mocked_value
pred_res = behav_est.eval_pdf(
indep_vals=indep_vals_input, dep_vals=dep_vals_input)
self.assertTrue(pred_res==actual_res) |
Hi, You are accessing You want to declare the class GbtEst_Test(unittest.TestCase):
@pytest.mark.usefixtures('mocka')
def test_1_eval_pdf(self, mocker):
...
estimator_mock = mocker.patch("behav_est.estimator.predict_proba") Declaring the parameter will cause pytest to inject the PS: In the future always try to post the full traceback along the example code when reporting bugs in projects. 👍 Hope that helps! |
Thank you @nicoddemus - I tried implementing your fix however, I seem to be receiving the "positional argument error" that OP mentioned. |
I'm using pytest 5.3.0 with pytest-mock 1.12.1, and in a pytest class I want to temporarily mock a function of an object returned by some other module function. When I use
test_calls_operation(mocker)
outside a test class, then themocker
arg gets filled in by pytest-mock as expected. However, when I declare the test as shown below, I gettest_calls_operation() missing 1 required positional argument: 'mocker'
. What am I doing wrong? I sifted through the documentation and especially StackOverflow, but I seem to miss the knack of getting themocker
arg` automatically set as needed.The text was updated successfully, but these errors were encountered: