Question

I have this piece of code:

import postie

def send_mail(self, outbox):
    try:
        postie.postmail(self.dbname, outbox)
    except postie.EmailDeliveryException:
        self.logger.error('Fail to send mail’)
        return False
    return True

And I want to test the case a postie.EmailDeliveryException is raised. So I mock out postie.postmail and put the exception as aside effect of its call:

import postie

@patch('postie.postmail')
def test_send_mail_False(self, postie_stub):
    ''' Mail send failed '''
    postie_stub.return_value = None
    postie_stub.side_effect = postie.EmailDeliveryException
    op = OutboxProcessor('db name', None, None)
    self.assertFalse(op.send_mail(Outbox()))

The above results in:

test_send_mail_False (test_outbox_processor.OutboxProcessorTestCase)
Mail send failed ... No handlers could be found for logger "outbox"
ok

Now I want to mock out the logger and check that the error function is also called in case of ‘EmailDeliveryException’. So I go:

@patch('postie.postmail')
@patch.object(Logger, 'error')
def test_send_mail_False(self, postie_stub, logger_stub):
    ''' Mail sending failed '''
    postie_stub.return_value = None
    postie_stub.side_effect = postie.EmailDeliveryException
    logger_stub.return_value = None

    op = OutboxProcessor('db name', None, None)
    self.assertFalse(op.send_mail(Outbox(), None))
    logger_stub.assert_called()

The result will be:

FAIL: test_send_mail_False (test_outbox_processor.OutboxProcessorTestCase)
Mail sending failed
AssertionError: True is not false

So it looks like the assertFalse does no longer succeed, (probably the exception is no longer raised). Anyone has any idea if anything interferes with my side_effect here? Thank you in advance!

Was it helpful?

Solution

You have incorrect order of patch decorators (or stub arguments). Here's an explanation from mock docs:

When you nest patch decorators the mocks are passed in to the decorated function in the same order they applied (the normal python order that decorators are applied). This means from the bottom up...

So it should be:

@patch.object(Logger, 'error')
@patch('postie.postmail')
def test_send_mail_False(self, postie_stub, logger_stub):
    ''' Mail sending failed '''
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top