Test Utilities
Note
This documentation page is aimed at developers who want to customize, change or extend the code of OpenWISP Utils in order to modify its behavior (e.g.: for personal or commercial purposes or to fix a bug, implement a new feature or contribute to the project in general).
If you aren't a developer and you are looking for information on how to use OpenWISP, please refer to:
openwisp_utils.tests.catch_signal
This method can be used to mock a signal call in order to easily verify that the signal has been called.
Usage example as a context-manager:
from openwisp_utils.tests import catch_signal
with catch_signal(openwisp_signal) as handler:
model_instance.trigger_signal()
handler.assert_called_once_with(
arg1="value1",
arg2="value2",
sender=ModelName,
signal=openwisp_signal,
)
openwisp_utils.tests.TimeLoggingTestRunner
This class extends the default test runner provided by Django and logs the time spent by each test, making it easier to spot slow tests by highlighting time taken by it in yellow (time shall be highlighted in red if it crosses the second threshold).
By default tests are considered slow if they take more than 0.3 seconds but you can control this with OPENWISP_SLOW_TEST_THRESHOLD.
In order to switch to this test runner you have set the following in your settings.py:
TEST_RUNNER = "openwisp_utils.tests.TimeLoggingTestRunner"
openwisp_utils.tests.capture_stdout
This decorator can be used to capture standard output produced by tests, either to silence it or to write assertions.
Example usage:
from openwisp_utils.tests import capture_stdout
@capture_stdout()
def test_something(self):
function_generating_output() # pseudo code
@capture_stdout()
def test_something_again(self, captured_ouput):
# pseudo code
function_generating_output()
# now you can create assertions on the captured output
self.assertIn("expected stdout", captured_ouput.getvalue())
# if there are more than one assertions, clear the captured output first
captured_error.truncate(0)
captured_error.seek(0)
# you can create new assertion now
self.assertIn("another output", captured_ouput.getvalue())
Notes:
If assertions need to be made on the captured output, an additional argument (in the example above is named
captured_output
) can be passed as an argument to the decorated test method, alternatively it can be omitted.A
StingIO
instance is used for capturing output by default but if needed it's possible to pass a customStringIO
instance to the decorator function.
openwisp_utils.tests.capture_stderr
Equivalent to capture_stdout
, but for standard error.
Example usage:
from openwisp_utils.tests import capture_stderr
@capture_stderr()
def test_error(self):
function_generating_error() # pseudo code
@capture_stderr()
def test_error_again(self, captured_error):
# pseudo code
function_generating_error()
# now you can create assertions on captured error
self.assertIn("expected error", captured_error.getvalue())
# if there are more than one assertions, clear the captured error first
captured_error.truncate(0)
captured_error.seek(0)
# you can create new assertion now
self.assertIn("another expected error", captured_error.getvalue())
openwisp_utils.tests.capture_any_output
Equivalent to capture_stdout
and capture_stderr
, but captures both
types of output (standard output and standard error).
Example usage:
from openwisp_utils.tests import capture_any_output
@capture_any_output()
def test_something_out(self):
function_generating_output() # pseudo code
@capture_any_output()
def test_out_again(self, captured_output, captured_error):
# pseudo code
function_generating_output_and_errors()
# now you can create assertions on captured error
self.assertIn("expected stdout", captured_output.getvalue())
self.assertIn("expected stderr", captured_error.getvalue())
openwisp_utils.tests.AssertNumQueriesSubTestMixin
This mixin overrides the assertNumQueries
assertion from the django test case to run in a subTest
so that the
query check does not block the whole test if it fails.
Example usage:
from django.test import TestCase
from openwisp_utils.tests import AssertNumQueriesSubTestMixin
class MyTest(AssertNumQueriesSubTestMixin, TestCase):
def my_test(self):
with self.assertNumQueries(2):
MyModel.objects.count()
# the assertion above will fail but this line will be executed
print("This will be printed anyway.")
openwisp_utils.test_selenium_mixins.SeleniumTestMixin
This mixin provides basic setup for Selenium tests with method to open URL and login and logout a user.