dimanche 1 mai 2016

Mocking an instance variable to test a method which will use it at initialisation time

I wrote the following class:

import numpy as np


class Product(object):

    def __init__(self, name, category, avg_daily_visitors, conversion_rate, days):
        self.name = name
        self.category = category
        self.avg_daily_visitors = avg_daily_visitors
        self.conversion_rate = conversion_rate
        self.days = days
        self.visitors, self.buyers = self._get_visitors_and_buyers_series(
            avg_daily_visitors=self.avg_daily_visitors,
            conversion_rate=self.conversion_rate,
            days=self.days)
        self.visitors_rolling_sum = _get_rolling_sum(
            self.visitors,
            window=30, 
            min_period=1)

    def _get_visitors_and_buyers_series(self, avg_daily_visitors,
                                        conversion_rate, days):
        visitors = np.random.poisson(lam=avg_daily_visitors, size=days)
        buyers = np.random.poisson(lam=conversion_rate, size=days)
        return visitors, buyers

    def _get_rolling_sum(self, series, window=30, min_period=1):
        """Compute a 30 days rolling sum of the series passed as an argument. 
        Note the rolling sum includes data only for the preceding 30 days, 
        not including today"""
        return

As you can see I didn't write yet the implementation of _get_rolling_sum() because I want to write a few unit tests beforehand.

I'm just a beginner, so apologies if I'm writing something stupid or I'm doing something entirely wrong. Feel free to flag this out.

Considering the function is launched when I create an instance of the object, I was thinking to mock the instance variable self.visitors and pass this list to the function _get_rolling_sum. In this way I could check the behaviour of the function using a deterministic input.

I've tried to do this in a file named test_program.py:

import nose
from nose.tools import assert_equal
from unittest.mock import patch
from simulator.product import Product


class TestProduct:

    def test_rolling_sums_creation(self):
        """Check rolling sum method is returning the correct results, given a
        deterministic input."""

        with patch("simulator.product.Product") as MockClass:
            instance = MockClass.return_value
            instance.visitors = [1, 0, 20, 7]
            import pdb; pdb.set_trace()
            result = instance._get_rolling_sum(series=[1, 0, 20, 7],
                                               window=30,
                                               min_period=1)
            expected = [0, 1, 1, 21]
            assert_equal(result, expected)

I thought the above test was mocking only the visitors instance variable, and that I could call any other method in the instance like it was a real Product object. However, I've realised result is actually not the result I would expect from the function _get_rolling_sum. Result is in fact another MagicMock object.

(Pdb) n
> /home/gianluca/git/simulator/simulator/test/test_product.py(45)test_rolling_sums_creation()
-> expected = [0, 1, 1, 21]
(Pdb) l
 40                 instance.visitors = [1, 0, 20, 7]
 41                 import pdb; pdb.set_trace()
 42                 result = instance._get_rolling_sum(series=[1, 0, 20, 7],
 43                                                    window=30,
 44                                                    min_period=1)
 45  ->             expected = [0, 1, 1, 21]
 46                 assert_equal(result, expected)
 47     
[EOF]
(Pdb) p result
<MagicMock name='Product()._get_rolling_sum()' id='140509529779840'>
(Pdb) 

How can I test the behaviour of _get_rolling_sum()?

Aucun commentaire:

Enregistrer un commentaire