Writing some unit tests in python and using MagicMock to mock out a method that accepts a JSON string as input. In my unit test, I want to assert that it is called with given arguments, however I run into issues with the assert statement, since the ordering of objects within the dict doesn't matter, besides in the assert statement for the string. Simplified example of what I am trying to achieve below.
mock_funct = MagicMock()
# mocked function called elsewhere
expected = {"a":"a", "b":"b"}
mock_funct.assert_called_once_with(json.dumps(expected))
The above may pass or may fail due to the arbitrary ordering of the keys within the dict when it is dumped to json, ie both '{"a":"a", "b":"b"}' and '{"b":"b", "a":"a"}' are valid dumps but one would fail and one would pass, however I would like to write the test so that either would pass.
Unfortunately, you'll need to do your own checking here. You can get the calls from the mock via it's call_args_list attribute (or, simply call_args in this case since you have already asserted that it is called only once). I'll assume you're using unittest in my example code -- but it should be easy enough to adapt for any testing framework ...
mock_funct.assert_called_once_with(mock.ANY)
call = mock_funct.call_args
call_args, call_kwargs = call # calls are 2-tuples of (positional_args, keyword_args)
self.assertEqual(json.loads(call_args[0]), expected)
I've still used assert_called_once_with to make sure that the function was only called once with a single positional argument, but then I open up the call to look at that argument to check that it is correct.
Related
I am adding some tests to existing not so test friendly code, as title suggest, I need to test if the complex method actually calls another method, eg.
class SomeView(...):
def verify_permission(self, ...):
# some logic to verify permission
...
def get(self, ...):
# some codes here I am not interested in this test case
...
if some condition:
self.verify_permission(...)
# some other codes here I am not interested in this test case
...
I need to write some test cases to verify self.verify_permission is called when condition is met.
Do I need to mock all the way to the point of where self.verify_permission is executed? Or I need to refactor the def get() function to abstract out the code to become more test friendly?
There are a number of points made in the comments that I strongly disagree with, but to your actual question first.
This is a very common scenario. The suggested approach with the standard library's unittest package is to utilize the Mock.assert_called... methods.
I added some fake logic to your example code, just so that we can actually test it.
code.py
class SomeView:
def verify_permission(self, arg: str) -> None:
# some logic to verify permission
print(self, f"verify_permission({arg=}=")
def get(self, arg: int) -> int:
# some codes here I am not interested in this test case
...
some_condition = True if arg % 2 == 0 else False
...
if some_condition:
self.verify_permission(str(arg))
# some other codes here I am not interested in this test case
...
return arg * 2
test.py
from unittest import TestCase
from unittest.mock import MagicMock, patch
from . import code
class SomeViewTestCase(TestCase):
def test_verify_permission(self) -> None:
...
#patch.object(code.SomeView, "verify_permission")
def test_get(self, mock_verify_permission: MagicMock) -> None:
obj = code.SomeView()
# Odd `arg`:
arg, expected_output = 3, 6
output = obj.get(arg)
self.assertEqual(expected_output, output)
mock_verify_permission.assert_not_called()
# Even `arg`:
arg, expected_output = 2, 4
output = obj.get(arg)
self.assertEqual(expected_output, output)
mock_verify_permission.assert_called_once_with(str(arg))
You use a patch variant as a decorator to inject a MagicMock instance to replace the actual verify_permission method for the duration of the entire test method. In this example that method has no return value, just a side effect (the print). Thus, we just need to check if it was called under the correct conditions.
In the example, the condition depends directly on the arg passed to get, but this will obviously be different in your actual use case. But this can always be adapted. Since the fake example of get has exactly two branches, the test method calls it twice to traverse both of them.
When doing unit tests, you should always isolate the unit (i.e. function) under testing from all your other functions. That means, if your get method calls other methods of SomeView or any other functions you wrote yourself, those should be mocked out during test_get.
You want your test of get to be completely agnostic to the logic inside verify_permission or any other of your functions used inside get. Those are tested separately. You assume they work "as advertised" for the duration of test_get and by replacing them with Mock instances you control exactly how they behave in relation to get.
Note that the point about mocking out "network requests" and the like is completely unrelated. That is an entirely different but equally valid use of mocking.
Basically, you 1.) always mock your own functions and 2.) usually mock external/built-in functions with side effects (like e.g. network or disk I/O). That is it.
Also, writing tests for existing code absolutely has value. Of course it is better to write tests alongside your code. But sometimes you are just put in charge of maintaining a bunch of existing code that has no tests. If you want/can/are allowed to, you can refactor the existing code and write your tests in sync with that. But if not, it is still better to add tests retroactively than to have no tests at all for that code.
And if you write your unit tests properly, they still do their job, if you or someone else later decides to change something about the code. If the change breaks your tests, you'll notice.
As for the exception hack to interrupt the tested method early... Sure, if you want. It's lazy and calls into question the whole point of writing tests, but you do you.
No, seriously, that is a horrible approach. Why on earth would you test just part of a function? If you are already writing a test for it, you may as well cover it to the end. And if it is so complex that it has dozens of branches and/or calls 10 or 20 other custom functions, then yes, you should definitely refactor it.
I have a main method that looks like this:
class Example:
...
def main(self):
self.one()
self.two(list)
self.three(self.four(4))
How to check if the calling main it calls the following methods inside it?
I have tried:
def setUp(self):
self.ex = example.Example()
def test_two(self):
# testing method two that has only list.append(int) and returns list
mock_obj = Mock()
self.ex.two(mock_obj, 1)
self.assertEqual(call.append(1),mock_obj.method_calls[0]) # works fine
mock_obj.method.called # throws False ...why?
def test_main(self):
with patch('example.Example') as a:
a.main()
print(a.mock_calls) # [call.main()]
...
def test_main(self):
mock_obj = Mock()
self.ex.main(mock_obj) # throws TypeError: main() takes exactly 1 argument (2 given)
print(mock_obj.method_calls) # expected one, two, three and four method calls
Realy need any help to be honest..
Using Python 2.6.6 with unittest and mock modules
With unit-testing you could in principle test if these four functions would actually be called. And, you could certainly do this by mocking all of them. However, you would need integration tests later anyway to be sure that the functions were called in the proper order, with the arguments in the proper order, arguments having values in the form expected by the callee, return values being in the expected form etc.
You can check all these things in unit-testing - but this has not much value, because if you have wrong assumptions about one of these points, your wrong assumptions will go into both your code and your unit-tests. That is, the unit-tests will test exactly against your wrong assumptions and will pass. Finding out about your wrong assumptions requires an integration test where the real caller and callee are brought together.
Summarized: Your main method is interaction dominated and thus should rather be tested directly by interaction-testing (aka integration-testing) rather than by unit-testing plus subsequent interaction-testing.
I have a function which returns a list of values. The values are animals which are in the store.
[dog, cat, horse, ...]
Now the problem is I don't know the exact values inside the list. These will differ. How can I unittest this function?
This is what I have now but I don't know how / on which values to check?
From unittest import TestCase, mock
..
def test_get_in_house_animals(self, ):
value = self.trade.get_in_house_animals()
self.assertTrue(value)
Can someone explain me the ususal method to use mock data when you don't know the exact return values?
In a unit-test environment you mock all dependencies out of your unit.
In your case the e.g. database/repository/api/whatever instance must be mocked in your environment. In unittests it is allowed to test against specific implementation of your unit/boundary context. In this case the datasource. You can check in a test if you call
self.trade.get_in_house_animals()
that a specific function e.g. hasBeenCalled('findAll') which is responsible for the result in get_in_house_animals.
In your case mock the httpClient and assert that your api-enpoint "hasBeenCalled". The result of the endpoint is out of your unit and not part of your unittest.
Hope unit-testing made a bit clearer.
import module
from x import X
class A:
def method():
return module.something(arg=X())
I created the following to unit test:
with patch('filename.module.something') as something_mock:
with patch('filename.X'): as x_mock:
a.method()
something_mock.assert_called_once_with(arg=x_mock.return_value)
x_mock.assert_called_once_with()
Someone mentioned that there is no need to mock filenme.X without an explanation. Is there other way to verify the call to something without mocking filename.X? How would I change the following assertion to verify the call?
something_mock.assert_called_once_with(arg=_____)
If create X is not a issue (i.e. db connection or network access) you can do your test without mock it.
You have follow alternatives:
Use mock's called attribute if you are not interested to check how your method call something_mock
Use mock.ANY if you would like to check that something_mock has called by arg keyword arg but you are not interested about what is the value
Use call_args to extract something_mock call arguments and by calls as tuple extract arg value
The first one is
assert something_mock.called
The second one is
something_mock.assert_called_once_with(arg=mock.ANY)
Finally the third one is
args, kwargs = something_mock.call_args
assert isinstance(kwarg['arg'], x.X)
Last option is quite the same to mock X but I wrote it just to show all possibilities.
When I have a parametrized pytest test like in the following case:
#parametrize('repetition', range(3))
#parametrize('name', ['test', '42'])
#parametrize('number', [3,7,54])
def test_example(repetition, name, number):
assert 1 = 1
the test runner prints out lines like follows:
tests\test_example.py:12: test_example[1-test-7]
where the parametrized values show up in the rectangular bracket next to the test functions name (test_example[0]). How can I access the content of the rectangular bracket (i.e. the string 0) inside the test? I have looked at the request
fixture, but could not find a suitable method for my needs.
To be clear: Inside the test method, I want to print the string 1-test-7, which pytest prints on the console.
How can I access the string 1-test-7, which pytest print out during a test?
I do not want to create this string by myself using something like
print str(repetition)+"-"+name+"-"+str(number)
since this would change every time I add a new parametrized argument to the test method.
In addition, if more complex objects are used in the parametrize list (like namedtuple), these objects are just references by a shortcut (e.g. object1, object2, ...).
Addendum: If I use the request fixture as an argument in my test method, I 'see' the string I would like to access when I use the following command
print request.keywords.node.__repr__()
which prints out something like
<Function 'test_example[2-test-3]'>
I am trying to find out how this method __repr__ is defined, in order to access directly the string test_example[2-test-3] from which I easily can extract the string I want, 2-test-3 in this example.
The solution makes use of the built-in request fixture which can be accessed as follows:
def test_example(repetition, name, number, request):
s = request.keywords.node.name
print s[s.find("[")+1:s.find("]")]
which will print the parameter string for each single parametrized test, so each parametrized test can be identified.