Unittest check if main called methods - python

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.

Related

How to assert a method has been called from another complex method in Python?

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.

Can I run unittest / pytest with python Optimization on?

I just added a few assert statements to the constructor of a class.
This has had the immediate effect of making about 10 tests fail.
Rather than fiddle with those tests I'd just like pytest to run the application code (not the test code obviously) with Python's Optimization switched on (-O switch, which means the asserts are all ignored). But looking at the docs and searching I can't find a way to do this.
I'm slightly wondering whether this might be bad practice, as arguably the time to see whether asserts fail may be during testing.
On the other hand, another thought is that you might have certain tests (integration tests, etc.) which should be run without optimisation, so that the asserts take effect, and other tests where you are being less scrupulous about the objects you are creating, where it might be justifiable to ignore the asserts.
asserts obviously qualify as "part of testing"... I'd like to add more to some of my constructors and other methods, typically to check parameters, but without making hundreds of tests fail, or have to become much more complicated.
The best way in this case would be to move all assert statements inside your test code. Maybe even switch to https://pytest.org/ as it is already using assert for test evaluation.
I'm assuming you can't in fact do this.
Florin and chepner have both made me wonder whether and to what extent this is desirable. But one can imagine various ways of simulating something like this, for example a Verifier class:
class ProjectFile():
def __init__(self, project, file_path, project_file_dict=None):
self.file_path = file_path
self.project_file_dict = project_file_dict
if __debug__:
Verifier.check(self, inspect.stack()[0][3]) # gives name of method we're in
class Verifier():
#staticmethod
def check(object, method, *args, **kwargs):
print(f'object {object} method {method}')
if type(object) == ProjectFile:
project_file = object
if method == '__init__':
# run some real-world checks, etc.:
assert project_file.file_path.is_file()
assert project_file.file_path.suffix.lower() == '.docx'
assert isinstance(project_file.file_path, pathlib.Path)
if project_file.project_file_dict != None:
assert isinstance(project_file.project_file_dict, dict)
Then you can patch out the Verifier.check method easily enough in the testing code:
def do_nothing(*args, **kwargs):
pass
verifier_class.Verifier.check = do_nothing
... so you don't even have to clutter your methods up with another fixture or whatever. Obviously you can do this on a module-by-module basis so, as I said, some modules might choose not to do this (integration tests, etc.)

How to test if a a method of main class is called from its wrapper

So i have a python class say
class Nested(object):
def method_test(self):
#do_something
The above class is being maintained by some other group so i can't change it. Hence we have a wrapper around it such that
class NestedWrapper(object):
self.nested = Nested()
def call_nested(object):
self.nested.method_test()
Now, I am writing test cases to test my NestedWrapper. How can i test that in one of my test, the underlying method of Nested.method_test is being called? Is it even possible?
I am using python Mock for testing.
UPDATE I guess I was implicitly implying that I want to do Unit Testing not a one off testing. Since most of the responses are suggesting me to use debugger, I just want to point out that I want it to be unit tested.
I think you can just mock Nested.method_test and make sure it was called...
with mock.patch.object(Nested, 'method_test') as method_test_mock:
nw = NestedWrapper()
nw.call_nested()
method_test_mock.called # Should be `True`
If using unittest, you could do something like self.assertTrue(method_test_mock.called), or you could make a more detailed assertion by calling one of the more specific assertions on Mock objects.

How to make sure that a function doesn't get called using Mock in a Django Application

I've already browsed through the mock documentations, and i've seen some examples where mock has been used. But, being a newbie, i find it hard to use mock in my tests.
test_scoring.py - I am creating a test to make sure that a function DOES NOT get called whenever i create an item.
The function compute_score() that i'd like to mock is part of a class HistoryItem.
What i got so far is this :
#test_scoring.py
#mock.patch('monitor.report.history_item.HistoryItem.compute_score')
def test_save_device_report(self):
....
result = factory.create_history_item(jsn)
# If the mocked method gets called after the above function is used, then there should be an error.
So, how do I mock the method? I'm quite confused on how to use it, because there are different ways in the resources i found.
I'd really appreciate your help.
When using the patch method as a decorator, you need to specify a second parameter to your test function:
#mock.patch('monitor.report.history_item.HistoryItem.compute_score')
def test_save_device_report(self, my_mock_compute_score):
....
# Assuming the compute_score method will return an integer
my_mock_compute_score.return_value = 10
result = factory.create_history_item(jsn)
# Then simulate the call.
score = result.compute_score() # This call could not be necessary if the previous
# call (create_history_item) make this call for you.
# Assert method was called once
my_mock_compute_score.assert_called_once()
# Also you can assert that score is equal to 10
self.assertEqual(score, 10)
Note that the mocks should be used only when you've tested the patched method or object in another test.
Where to patch? -> https://docs.python.org/3/library/unittest.mock.html#where-to-patch
Edit
This patch is gonna to avoid a real call to compute_score(). However, after reread your post I can see you want to assert your function doesn't get called.
Hopefully, the called attribute is present in every mock you make, so for that you can use:
#mock.patch('monitor.report.history_item.HistoryItem.compute_score')
def test_save_device_report(self, my_mock_compute_score):
...
result = factory.create_history_item(jsn)
self.assertFalse(my_mock_compute_score.called)
...

Assert mocked function called with json string in python

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.

Categories

Resources