How do I make fun of a class that has unrelated methods? For example, this class has @classmethod and @staticmethod :
class Calculator(object): def __init__(self, multiplier): self._multiplier = multiplier def multiply(self, n): return self._multiplier * n @classmethod def increment(cls, n): return n + 1 @staticmethod def decrement(n): return n - 1 calculator = Calculator(2) assert calculator.multiply(3) == 6 assert calculator.increment(3) == 4 assert calculator.decrement(3) == 2 assert Calculator.increment(3) == 4 assert Calculator.decrement(3) == 2
The above describes my question in some detail. Below is a working example demonstrating the things I tried.
The Machine class contains an instance of Calculator . I will test Machine with the Calculator layout. To demonstrate my problem, Machine calls unrelated methods through the Calculator instance and through the Calculator class:
class Machine(object): def __init__(self, calculator): self._calculator = calculator def mult(self, n): return self._calculator.multiply(n) def incr_bound(self, n): return self._calculator.increment(n) def decr_bound(self, n): return self._calculator.decrement(n) def incr_unbound(self, n): return Calculator.increment(n) def decr_unbound(self, n): return Calculator.decrement(n) machine = Machine(Calculator(3)) assert machine.mult(3) == 9 assert machine.incr_bound(3) == 4 assert machine.incr_unbound(3) == 4 assert machine.decr_bound(3) == 2 assert machine.decr_unbound(3) == 2
All functional codes above work fine. The next part does not work.
I am creating a mock Calculator for use in testing Machine :
from mock import Mock def MockCalculator(multiplier): mock = Mock(spec=Calculator, name='MockCalculator') def multiply_proxy(n): '''Multiply by 2*multiplier instead so we can see the difference''' return 2 * multiplier * n mock.multiply = multiply_proxy def increment_proxy(n): '''Increment by 2 instead of 1 so we can see the difference''' return n + 2 mock.increment = increment_proxy def decrement_proxy(n): '''Decrement by 2 instead of 1 so we can see the difference''' return n - 2 mock.decrement = decrement_proxy return mock
In the unit test below, related methods use the MockCalculator as I hoped. However, calls to Calculator.increment() and Calculator.decrement() still use Calculator :
import unittest class TestMachine(unittest.TestCase): def test_bound(self): '''The bound methods of Calculator are replaced with MockCalculator''' machine = Machine(MockCalculator(3)) self.assertEqual(machine.mult(3), 18) self.assertEqual(machine.incr_bound(3), 5) self.assertEqual(machine.decr_bound(3), 1) def test_unbound(self): '''Machine.incr_unbound() and Machine.decr_unbound() are still using Calculator.increment() and Calculator.decrement(n), which is wrong. ''' machine = Machine(MockCalculator(3)) self.assertEqual(machine.incr_unbound(3), 4)
So, I'm trying to set Calculator.increment() and Calculator.decrement() :
def MockCalculatorImproved(multiplier): mock = Mock(spec=Calculator, name='MockCalculatorImproved') def multiply_proxy(n): '''Multiply by 2*multiplier instead of multiplier so we can see the difference''' return 2 * multiplier * n mock.multiply = multiply_proxy return mock def increment_proxy(n): '''Increment by 2 instead of 1 so we can see the difference''' return n + 2 def decrement_proxy(n): '''Decrement by 2 instead of 1 so we can see the difference''' return n - 2 from mock import patch @patch.object(Calculator, 'increment', increment_proxy) @patch.object(Calculator, 'decrement', decrement_proxy) class TestMachineImproved(unittest.TestCase): def test_bound(self): '''The bound methods of Calculator are replaced with MockCalculator''' machine = Machine(MockCalculatorImproved(3)) self.assertEqual(machine.mult(3), 18) self.assertEqual(machine.incr_bound(3), 5) self.assertEqual(machine.decr_bound(3), 1) def test_unbound(self): '''machine.incr_unbound() and Machine.decr_unbound() should use increment_proxy() and decrement_proxy(n). ''' machine = Machine(MockCalculatorImproved(3)) self.assertEqual(machine.incr_unbound(3), 5) self.assertEqual(machine.decr_unbound(3), 1)
Even after fixing, unrelated methods want an instance of Calculator as an argument:
TypeError: unbound increment_proxy () method should be called with the Calculator instance as the first argument (int int is used instead)
How do I make fun of the Calculator.increment() class method and the static Calculator.decrement() method?