6

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')

1 Answer 1

9

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])
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.