Unittest implementation Python property
Question: I have a class with the following property `clusters`:

    
    
    import numpy as np
    
    class ClustererKmeans(object):
    
        def __init__(self):
            self.clustering = np.array([0, 0, 1, 1, 3, 3, 3, 4, 5, 5])
    
        @property
        def clusters(self):
            assert self.clustering is not None, 'A clustering shall be set before obtaining clusters'
            return np.unique(self.clustering)
    

I now want to write a unittest for this simple property. I start off with:

    
    
    from unittest import TestCase, main
    from unittest.mock import Mock
    
    class Test_clusters(TestCase):
    
        def test_gw_01(self):
            sut = Mock()
            sut.clustering = np.array([0, 0, 1, 1, 3, 3, 3, 4, 5, 5])
            r = ClustererKmeans.clusters(sut)
            e = np.array([0, 1, 3, 4, 5])
            # The following line checks to see if the two numpy arrays r and e are equal,
            # and gives a detailed error message if they are not. 
            TestUtils.equal_np_matrix(self, r, e, 'clusters')
    
    if __name__ == "__main__":
        main()
    

However, this does not run.

    
    
    TypeError: 'property' object is not callable
    

I next change the line `r = ClustererKmeans.clusters(sut)` to the following:

    
    
    r = sut.clusters
    

But again, I get an unexpected error.

    
    
    AssertionError: False is not true : r shall be a <class 'numpy.ndarray'> (is now a <class 'unittest.mock.Mock'>)
    

Is there an easy way to test the implementation of a property in Python using
the unittest framework?


Answer: To [call property](https://docs.python.org/2/howto/descriptor.html#invoking-
descriptors) directly you can replace in your original code
`ClustererKmeans.clusters(sut)` by `ClustererKmeans.clusters.__get__(sut)`.

Even if I'm a mocking enthusiastic IMHO this case is not a good example to
apply it. Mocking are useful to remove dependencies from class and resources.
In your case `ClustererKmeans` have a empty constructor and there isn't any
dependency to break. You can do it by:

    
    
    class Test_clusters(TestCase):
        def test_gw_01(self):
            sut = ClustererKmeans()
            sut.clustering = np.array([0, 0, 1, 1, 3, 3, 3, 4, 5, 5])
            np.testing.assert_array_equal(np.array([0, 1, 2, 3, 4, 5]),sut.clusters)
    

If you would use mocking you can patch `ClustererKmeans()` object by using
`unittest.mock.patch.object`:

    
    
    def test_gw_01(self):
        sut = ClustererKmeans()
        with patch.object(sut,"clustering",new=np.array([0, 0, 1, 1, 3, 3, 3, 4, 5, 5])):
            e = np.array([0, 1, 3, 4, 5])
            np.testing.assert_array_equal(np.array([0, 1, 2, 3, 4, 5]),sut.clusters)
    

...but why use patch when python give to you a simple and direct way to do it?

Another way to use mock framework should be trust `numpy.unique` and check if
the property do the right work:

    
    
    @patch("numpy.unique")
    def test_gw_01(self, mock_unique):
        sut = ClustererKmeans()
        sut.clustering = Mock()
        v = sut.clusters
        #Check is called ....
        mock_unique.assert_called_with(sut.clustering)
        #.... and return
        self.assertIs(v, mock_unique.return_value)
    
        #Moreover we can test the exception
        sut.clustering = None
        self.assertRaises(Exception, lambda s:s.clusters, sut)
    

I apologize for some errors but I don't test the code. I you notify to me I
will fix all as soon as possible.

