I am a pythoner. At these days I am driving myself to do a more complete unit test on some core module in my project. Since we always do unit test with methods 'assertEqual', 'assertTrue' and so on, these methods all require a return value from the function being tested, I am wondering how to do a plain unit test on some function without a return value.
I would like to show a tiny example here, how to test function def foo(self, msg) in HelloTest?
class HelloTest(object): def foo(self, msg): MSG = msg.upper() self.bar(MSG) def bar(self, MSG): print MSG
If a method is not returning anything through the "return" statement (void method), it may return data through its arguments. In this case, you can test the data returned in any argument. Else if a method is not returning any data through its arguments, it may change values of its instance variables.
As another answer mentioned, you can use the Python mock library to make assertions about calls to functions/methods
from mock import patch from my_module import HelloTest import unittest class TestFoo(unittest.TestCase): @patch('hello.HelloTest.bar') def test_foo_case(self, mock_bar): ht = HelloTest() ht.foo("some string") self.assertTrue(mock_bar.called) self.assertEqual(mock_bar.call_args[0][0], "SOME STRING")
This patches out the bar
method on HelloTest and replaces it with a mock object that records calls against it.
Mocking is a bit of a rabbit hole. Only do it when you absolutely have to because it does make your tests brittle. You'll never notice an API change for a mocked object for instance.
I don't quite understand why everybody wants to check that foo calls bar.
Foo has some functionality and this functionality needs to be tested. If foo is using bar to do this should not be of my concern.
The desired result is that after foo(msg)
is called, is that msg.upper()
is sent to stdout.
You can redirect stdout to a string buffer and check if the content of this string buffer matches what you expect.
Example:
import sys import unittest from io import TextIOWrapper, BytesIO class TestScript(unittest.TestCase): def setUp(self): self._old_stdout = sys.stdout sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding) def _output(self): self._stdout.seek(0) return self._stdout.read() def test_foo(self): hello_test = HelloTest() hello_test.foo("blub") self.assertEqual(self._output(), "BLUB") def tearDown(self): sys.stdout = self._old_stdout self._stdout.close()
You can also do that for stdin (and write to stdin to mock some input) and you can subclass TestIOWrapper if you need anything special to be done, like allowing non-unicode text to be sent to sys.stdout
without using sys.stdout.buffer
(Python 2 vs. Python 3). There is an example for that in this SO answer. When you (still) use Python 2 only, then using StringIO
might be better than using the io module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With