Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock: assert_called_once_with a numpy array as argument

I have a method in a class that I want to test using the unittest framework, using Python 3.4. I prefer to work using a Mock as the object of the class to test, as explained in Daniel Arbuckle's Learning Python Testing.

The problem

This is what I would do:

class Test_set_initial_clustering_rand(TestCase):

    def setUp(self):
        self.sut = Mock()

    def test_gw_01(self):
        self.sut.seed = 1
        ClustererKmeans.set_initial_clustering_rand(self.sut, N_clusters=1, N_persons=6)
        e = np.array([0, 0, 0, 0, 0, 0])
        self.sut.set_clustering.assert_called_once_with(e)

This would check if the function set_clustering is called once with the expected argument. The framework tries to compare the two arguments using actual_arg == expected_arg. This goes wrong however if the argument is a numpy array.

Traceback (most recent call last):
  File "/Users/.../UT_ClustererKmeans.py", line 184, in test_gw_01
    self.sut.set_clustering.assert_called_once_with(e)
  File "/Users/.../anaconda/lib/python3.4/unittest/mock.py", line 782, in assert_called_once_with
    return self.assert_called_with(*args, **kwargs)
  File "/Users/.../anaconda/lib/python3.4/unittest/mock.py", line 769, in assert_called_with
    if expected != actual:
  File "/Users/.../anaconda/lib/python3.4/unittest/mock.py", line 2001, in __ne__
    return not self.__eq__(other)
  File "/Users/.../anaconda/lib/python3.4/unittest/mock.py", line 1997, in __eq__
    return (other_args, other_kwargs) == (self_args, self_kwargs)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Comparing numpy arrays is done in a different way, but the comparison is made inside the unittest framework. What would be the best way to work around this problem?

Solution 1

I found the following solution, and want to share it here and hope to get feedback on it.

class Test_set_initial_clustering_rand(TestCase):

    def setUp(self):
        '''
        This class tests the method set_initial_clustering_rand,
        which makes use of the function set_clustering. For the
        sut is concerned, all that set_clustering has to do is
        to store the value of the input clustering. Therefore,
        this is mocked here.
        '''
        self.sut = Mock()
        self.sut.seed = 1
        def mock_set_clustering(input_clustering):
            self.sut.clustering = input_clustering
        self.sut.set_clustering.side_effect = mock_set_clustering

    def test_gw_01(self):
        ClustererKmeans.set_initial_clustering_rand(self.sut, N_clusters=1, N_persons=6)
        r = self.sut.clustering
        e = np.array([0, 0, 0, 0, 0, 0])
        TestUtils.equal_np_matrix(self, r, e, 'clustering')
like image 877
physicalattraction Avatar asked Jan 05 '15 14:01

physicalattraction


1 Answers

You can access to called argument of a Mock() by call_args property and compare two numpy array by np.testing.assert_array_equal as pointed out in https://stackoverflow.com/a/14921351/4101725 and https://stackoverflow.com/a/14249723/4101725

def test_gw_01(self):
    m = Mock()
    ClustererKmeans.set_initial_clustering_rand(m, N_clusters=1, N_persons=6)
    self.assertTrue(m.set_clustering)
    np.testing.assert_array_equal(np.array([0, 0, 0, 0, 0, 0]),m.set_clustering.call_args[0][0])
like image 174
Michele d'Amico Avatar answered Oct 21 '22 13:10

Michele d'Amico