0

When mocking objects, there are some instruments, which allow to change the result of a function.

Let's say, there is some class:

class Worker:

    def do_work(self):
        return perform_operation()

And I want to test some cases, when do_work() raises several exceptions in different situations:

@patch(
    'my.package.Worker.do_work',
    Mock(side_effect=[exc.VeryBadError, exc.NotThatBadError]
))
def test_worker_raise_errors():
    worker_user.call_worker()

But there is no way to pass several errors to side_effects like above, it would run only once and Fail only for exc.VeryBadError.

When I want to find a way to launch test_worker_raise_errors() twice for each exception, but w/o creating each test function per exception.

Is there a way to launch one test several times for each exception as a side effect and to see 2 Fails in this case?

Vitalii Dmitriev
  • 739
  • 1
  • 8
  • 18
  • 1
    This can be done as some sort of a parameterized test. Check this answer: https://stackoverflow.com/questions/32899/how-do-you-generate-dynamic-parameterized-unit-tests-in-python – rdas Oct 11 '19 at 09:21

1 Answers1

1

This simple example will give you the hint:

from unittest.mock import Mock

mock = Mock(
    side_effect=[
        AssertionError('Error 1'), 
        AttributeError('Error 2'),
    ]
)

try:
    mock()
except AssertionError as e:     # Catch the exception so that the execution can continue and we can test further.
    print(e)

try:
    mock()
except AttributeError as e:     # Catch the exception so that the execution can continue and we can test further.
    print(e)

Output:

Error 1
Error 2

You can use self.assertRaises(...) to make it a little bit cleaner.

Dipen Dadhaniya
  • 4,550
  • 2
  • 16
  • 24
  • Understood, but Is there any way to make a function be called twice, instead of calling a mocked instance twice explicitly? E.g.: I want to check it for 5 different exceptions, but don't want to call tested code 5 times. – Vitalii Dmitriev Oct 11 '19 at 13:00
  • Suppose you mock `do_work` like this (side_effect=[exc.VeryBadError, exc.NotThatBadError]), then `worker_user.call_worker()` will start execution and when it calls `do_work` for the first time it will raise `exc.VeryBadError` and when it calls `do_work` for the second time it will raise `exc.NotThatBadError`. I think this is what you want. – Dipen Dadhaniya Oct 11 '19 at 13:03