Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unittest the sequence of function calls made insde a fuction [python]

I would like to unittest a fuction and assert if the sequence of function calls made inside the function workflow(). Something like,

      [1st called] fetch_yeargroup_ls()
      [2nd called] invoke_get_links()....... 

I searched across many discussions but never found one answering my question.

like image 647
Madhan Gokul Avatar asked Sep 28 '22 02:09

Madhan Gokul


2 Answers

If you are using mock you can create mocks as attributes of a parent mock, when patching out those functions:

try:
    # Python 3
    from unittest.mock import MagicMock, patch, call
except ImportError:
    # Python 2, install from PyPI first
    from mock import MagicMock, patch, call
import unittest

from module_under_test import function_under_test

class TestCallOrder(unittest.TestCase):
    def test_call_order(self):
        source_mock = MagicMock()
        with patch('module_under_test.function1', source_mock.function1), \
                patch('module_under_test.function2', source_mock.function2), \
                patch('module_under_test.function3', source_mock.function3)

            # the test is successful if the 3 functions are called in this
            # specific order with these specific arguments:
            expected = [
                call.function1('foo'),
                call.function2('bar'),
                call.function3('baz')
            ]

            # run your code-under-test
            function_under_test()

            self.assertEqual(source_mock.mock_calls, expected)

Because the 3 functions are attached to source_mock, all calls to them are recorded on the parent mock object in the Mock.mock_calls attribute and you can make assertions about their call order.

I attached the 3 function mocks simply by looking them up as attributes on the source_mock object, but you could also use the Mock.attach_mock() method to attach mocks you created in a different way to a parent.

like image 124
Martijn Pieters Avatar answered Oct 24 '22 03:10

Martijn Pieters


In my opinion, the real purpose of testing or specifically TDD is to have better designed code. If writing tests for your code is becoming difficult, then it signifies that your code is highly coupled and you need to refactor it. Besides, writing tests that assert the order of the functions, make tests too coupled to the code and highly fragile.

With that said, you can test the order, in a little hackish way though. Say, you have two functions named func_a and func_b, and you want to ensure func_a is called before func_b. Replace func_a with a mock that returns some random value such that it stops execution from happening any further. Mock func_b as well, and ensure func_a is called and func_b is not called. You need to do this for other permutations as well.

like image 40
hspandher Avatar answered Oct 24 '22 02:10

hspandher