Python unit tests: How to patch an entire class and methods

Viewed 1289

I am trying to write unittests for existing code which is poorly written and I'm finding it very hard to unit test.

def pay(self):
    fraud = NewFraudCheck()
    result, transaction = fraud.verify_transaction()

the test I have at the moment, I am patching the NewFraudCheck class

@patch checkout.pay.NewFraudCheck
def test_pay(self, mock_fraud_check):
    mock_fraud_check.verify_transaction.assert_called()

The test is failing with a ValueError, stating that verify_transaction is not returning enough values to unpack.

I have tried adding

mock_fraud_check.verify_data.return_value = (1, 1231231)

however this doesn't seemt o have any effect.

1 Answers

There are a few issues I'll point out, but the question is missing a few details so hopefully I can address them all in one shot:

  1. Your syntax here is wrong: @patch checkout.pay.NewFraudCheck. It should be @patch('checkout.pay.NewFraudCheck')

  2. There is a missing class somewhere that has the function pay(self) on it. That class lives inside a module somewhere which is important to properly mock NewFraudCheck. I'll refer to that missing module as other.

  3. NewFraudCheck needs to be patched at the point where it's looked up. That means, in the mystery module other where there's a class that has pay(self) defined in it, there's presumably an import of from pay import NewFraudCheck. That is where NewFraudCheck is looked up, so your patch will need to look like this: @patch('checkout.other.NewFraudCheck). More info here: http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch

  4. You need to assign/use the return value of your patch, not access verify_transaction directly off of the mock. For instance, it should read like this: mock_fraud_check.return_value.verify_transaction.return_value = (1, 1231231). Notice the inclusion of return_value.

The final test I came up with looked like this and passed:

    @mock.patch('checkout.other.NewFraudCheck')
    def test_pay(self, mock_fraud_check):
        # This is the class that lives in mystery module, 'checkout.other' and calls pay()
        other_class = SomeOtherClass()
        mock_fraud_check.return_value.verify_transaction.return_value = (1, 1231231)
        other_class.pay()
        mock_fraud_check.return_value.verify_transaction.assert_called()
Related