62

I'm having issues raising an exception from a function in my test:

### Implemetation
def MethodToTest():
    myVar = StdObject()
    try:
        myVar.raiseError() # <--- here
        return True
    except Exception as e:
        # ... code to test
        return False

### Test file
@patch('stdLib.StdObject', autospec=True)
def test_MethodeToTest(self, mockedObjectConstructor):
    mockedObj = mockedObjectConstructor.return_value
    mockedObj.raiseError.side_effect = Exception('Test') # <--- do not work
    ret = MethodToTest()
    assert ret is False

I would like to raiseError() function to raise an error.

I found several examples on SO, but none that matched my need.

user4780495
  • 2,642
  • 2
  • 18
  • 24
  • maybe this could help you http://stackoverflow.com/questions/2052390/manually-raising-throwing-an-exception-in-python – Alex L Nov 22 '16 at 07:52
  • 1
    Are you sure you're patching in the right place (where it's imported, not where it's imported *from*)? – jonrsharpe Nov 22 '16 at 07:54
  • I _think_ that I patch in the right place, as my other tests are working as expected. – user4780495 Nov 22 '16 at 08:26
  • [side_effect()](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.side_effect) supports raising an exception. Maybe you patch the wrong object. – guettli May 03 '21 at 14:26

2 Answers2

78

I changed

@patch('stdLib.StdObject', autospec=True)

to

@patch('stdLib.StdObject', **{'return_value.raiseError.side_effect': Exception()})

and removed the # <--- do not work line.

It's now working.

This is a good example.

EDIT:

mockedObj.raiseError.side_effect = Mock(side_effect=Exception('Test'))

also works.

ischenkodv
  • 4,205
  • 2
  • 26
  • 34
user4780495
  • 2,642
  • 2
  • 18
  • 24
  • 26
    This work for me: mockedObj.side_effect = Exception('Test') – Hai Nguyen Dec 24 '18 at 06:18
  • 14
    arguments to `@patch` are passed onto the constructor of `Mock`, so using `@patch('stdLib.StdObject', side_effect=Exception('Test'))` works as well and is shorter. – luto Jan 20 '19 at 14:41
  • 1
    @luto comment worked for me. Patching `mockedObj.raiseError.side_effect` did not actually raise an error. – verboze Jun 01 '22 at 22:43
17

Ok, your answer you provided is valid, but you changed how you did it (which is fine. To fix your original problem, you need to assign a function to side_effect, not the results or an object:

def my_side_effect():
    raise Exception("Test")

@patch('stdLib.StdObject', autospec=True)
def test_MethodeToTest(self, mockedObjectConstructor):
    mockedObj = mockedObjectConstructor.return_value
    mockedObj.raiseError.side_effect = my_side_effect # <- note no brackets, 
    ret = MethodToTest()
    assert ret is False

Hope that helps. Note, if the target method takes args, the side effect needs to take args as well (I believe).

Jmons
  • 1,766
  • 17
  • 28
  • 13
    You do not need to assign a function; that's just one of the options, but it is not the best here. Just assign the exception to `side_effect` instead: `mockedObj.raiseError.side_effect = Exception("Test")`. – Martijn Pieters Feb 10 '18 at 18:03
  • 1
    You don't have to no: and his edit has a third way of doing it where he is making a Mock with the side effect set, but its still a valid, and good thing to know how to do in testing. Theres nothing wrong with doing it this way, especially as it lets you extend your test later? – Jmons Feb 17 '18 at 20:10
  • 1
    Did the OP edit their question? It looks like they are already assigning to `side_effect`, and the suggestion from @MartijnPieters looks exactly like the line that they commented "do not work". – Davos Nov 19 '18 at 00:31
  • I don't think the question was edited. I think at the time (bering in mind this was Nov 2016, and its now Nov 2018), my understanding of side_effect was that it was called as a function - which isn't true, You should be able to do things like `side_effect = 12`, Given that the OP give a radically different answer that they then accepted, I wonder if there were other, unpasted, code bugs. If i remember rightly I copied this code into a shell script and tested and also saw it 'not working' before I patched it to use a function. But that was two years ago! Now a better python programmer every day – Jmons Nov 23 '18 at 09:41