'How do I mock a function with no parameters that sets a class attribute for Python unit tests?
My class, Foo, has a calculate method that takes no parameters, makes a call to a database and does some calculations using class attributes, and sets another class attribute, calculation_results (which is a dict).
I'm trying to mock a separate function that includes a call to Foo.calculate().
I tried something like the below, where mock_calculate was a function defined in my test class:
def mock_calculate():
pass
@mock.patch("path.Foo.validate", new=mock_calculate)
@mock.patch("path.Foo")
def test_func_that_calls_foo(self, mock_foo):
mock_foo.return_value.calculation_results = {first_calc : 1, second_calc: 2, database_mismatches : []}
func_that_calls_foo(#TEST_INPUT)
#assertions
This code does set the calculation_result attribute, but it still calls the actual calculate function, which fails when it tries to hit the database. How can I set Foo.calculation_results directly and also not actually call calculate()? The fact that calculate() doesn't take params or return anything is making it tough to follow most examples I see of mocking--otherwise I could just set a return_value or, inside the function, set the attribute based on the params passed.
Solution 1:[1]
You can simply also patch the method calculate
, and then the real implementation will not be called.
I might implement this differently though, using a lazy operator and a PropertyMock. Code sample:
from unittest import mock
class Foo:
def __init__(self):
self._calculated_results = {}
@property
def calculated_results(self):
if not self._calculated_results:
self._calculated_results = self.calculate()
return self._calculated_results
def do_something_with_results(self):
return self.calculated_results
def calculate(self):
assert False, 'Ensure this method is not called, since it would call the database'
return {}
@mock.patch.object(Foo, 'calculated_results', new_callable=mock.PropertyMock, return_value={'key': 'value'})
def test_func_that_calls_foo(mock_foo):
x = Foo().do_something_with_results()
assert x == {'key': 'value'}
test_func_that_calls_foo()
This test function passes with the patch, and fails without the patch: AssertionError: Ensure this method is not called, since it would call the database
.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | physicalattraction |