mdickin mdickin - 1 year ago 57
Python Question

Mocks not getting hit in Python unit tests

I'm new to Python, but I've done quite a bit of unit testing in C# and JavaScript. I'm having trouble figuring out the mocking framework in Python. Here's what I have (trimmed down):

import ims.repository.invoice_repository as invoiceRepository
import logging

logger = logging.getLogger(__name__)

def update_invoice_statuses(invoices):
for invoice in invoices:
dbInvoice = invoiceRepository.get(invoice.invoice_id)
print("dbInvoice is %s" % dbInvoice) #prints <MagicMock etc.>

if dbInvoice is None:
logger.error("Unable to update status for invoice %d" % invoice.invoice_id)

from unittest import TestCase, mock
import logging
import as business

class UpdateInvoiceTests(TestCase):
def test_invoiceDoesNotExist_logsErrorAndContinues(self, invoiceRepoMock, loggerMock):
invoice = Invoice(123)
invoice.set_status(InvoiceStatus.Filed, None)


loggerMock.error.assert_called_once_with("Unable to update status for invoice 123")

The test fails with

AssertionError: Expected 'get' to be called once. Called 0 times.

statement in
gets hit, though, because I see the output of

dbInvoice is <MagicMock name='invoiceRepository.get()' id='xxxx'>

Any idea what I'm doing wrong here?

Edit: After @chepner's help, I ran into another assertion error and realized it was because I should be using
invoiceRepoMock.get.return_value = None
rather than

Answer Source

The mock arguments to your test function are swapped. The inner decorator (for the logger) is applied first, so the mock logger should be the first argument to your method.

def test_invoiceDoesNotExist_logsErrorAndContinues(self, loggerMock, invoiceRepoMock):