Last active
June 22, 2021 09:32
-
-
Save paul-butcher/a9c21ed662bc3f89db01f1ef514efb9c to your computer and use it in GitHub Desktop.
Demonstration of using Mock.side_effect to return a different value on each call.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| Using Mock.side_effect with a list to provide multiple return values | |
| """ | |
| from unittest import mock | |
| class MyClass: | |
| @staticmethod | |
| def hello(lang): | |
| # Imagine that this function makes an unreliable, expensive, or slow network call | |
| # to a translation service or something. | |
| # You will want to mock it in unit tests to ensure that the function | |
| # executes in reasonable time and without having to worry about network or credentials etc. | |
| # In this case, it's a function that gives a greeting in the requested | |
| # language. So you can imagine that it might check the current time and return | |
| # a morning, afternoon, or evening greeting. | |
| # Anything that returns a different result based on time of day needs to be mocked, | |
| # otherwise tests that pass in the morning will fail in the evening. | |
| if lang == 'deu': | |
| return 'guten Tag' | |
| if lang == 'nob': | |
| return 'god dag' | |
| @staticmethod | |
| def greet(): | |
| return f'{MyClass.hello("deu")}, world! {MyClass.hello("nob")}, world!' | |
| def bare_greet(): | |
| return f'{bare_hello("cym")}, world! {bare_hello("fra")}, world!' | |
| def bare_hello(lang): | |
| if lang == 'cym': | |
| return 'bore da' | |
| if lang == 'fra': | |
| return 'bonjour' | |
| def test_class_greet(): | |
| """ | |
| You can patch out the method inside the test method, | |
| giving an iterable to side_effect to cope with the fact that it is called | |
| multiple times. | |
| """ | |
| with mock.patch.object(MyClass, 'hello') as mock_hello: | |
| print('PATCHED: ') | |
| mock_hello.side_effect = [ | |
| 'guten abend', 'god kveld' | |
| ] | |
| # You can assert, as normal, that the value returned by the function is what you expect, | |
| # given the two values returned from the mock. | |
| assert MyClass.greet() == 'guten abend, world! god kveld, world!' | |
| # To be sure that the right arguments were provided in the right order, | |
| # you can use assert_has_calls. | |
| # This, in conjuction with asserting the value above, should give confidence that all is in order inside | |
| # `greet` and that | |
| assert mock_hello.call_count == 2 | |
| mock_hello.assert_has_calls([mock.call('deu'), mock.call('nob')]) | |
| def test_bare_greet(): | |
| with mock.patch('__main__.bare_hello') as mock_hello: | |
| print('PATCHED: ') | |
| mock_hello.side_effect = [ | |
| 'noswaith dda', 'bonsoir' | |
| ] | |
| assert bare_greet() == 'noswaith dda, world! bonsoir, world!' | |
| assert mock_hello.call_count == 2 | |
| mock_hello.assert_has_calls([mock.call('cym'), mock.call('fra')]) | |
| if __name__ == '__main__': | |
| print('NORMAL (Class): ') | |
| MyClass.greet() | |
| test_class_greet() | |
| print('NORMAL (bare):') | |
| bare_greet() | |
| test_bare_greet() | |
| print('DONE') | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment