Dzmitry
Dzmitry

Reputation: 13

mock in unittest Python

I want to replace randint in the method multi with 'mock' in Python. My code doesn't work. How can I make it work?

from random import randint
import unittest
from unittest import mock


class Calculator:

    def __init__(self, number):
        self.number = number
        self.number2 = randint(1, 5)

    def multi(self):
        return self.number * self.number2


class CalculatorTest(unittest.TestCase):

    NUMBER = Calculator(3)

    @mock.patch('random.randint', return_value=4)
    def test_multi(self):
        actual_result = self.NUMBER.multi()
        expected_result = 12
        self.assertEqual(actual_result, expected_result,
                         f'Actual result {actual_result}, expected {expected_result}')

Upvotes: 1

Views: 109

Answers (1)

chepner
chepner

Reputation: 532112

You are calling randint when NUMBER is defined, not when you call its multi method. The patch is too late. Instead, define NUMBER in the test itself. Further, since you used from random import randint, the name to patch is randint, not random.randint.

class CalculatorTest(unittest.TestCase):

    @mock.patch('randint', return_value=4)
    def test_multi(self, mock_rand):
        NUMBER = Calculator(3)
        actual_result = NUMBER.multi()
        expected_result = 12
        self.assertEqual(actual_result, expected_result,
                         f'Actual result {actual_result}, expected {expected_result}')

If NUMBER must be defined as class attribute (though that would be atypical), you can use mock.patch as a context manager rather than a decorator.

class CalculatorTest(unittest.TestCase):

    with mock.patch('randint', return_value=4)
        NUMBER = Calculator(3)

    def test_multi(self):
        actual_result = self.NUMBER.multi()
        expected_result = 12
        self.assertEqual(actual_result, expected_result,
                         f'Actual result {actual_result}, expected {expected_result}')

More commonly, though, you would use the setUp method to define a fixture, rather than sharing an instance across tests. You can either decorate setUp or us the context manager.

class CalculatorTest(unittest.TestCase):

    def setUp(self):
        with mock.patch('randint', return_value=4):
            self.NUMBER = Calculator(3)

    ...

or

class CalculatorTest(unittest.TestCase):

    @mock.patch('randint', return_value=4)
    def setUp(self, mock_rand):
        self.NUMBER = Calculator(3)

    ...

Upvotes: 2

Related Questions