我有一类具有以下属性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)


我现在想为此简单属性编写一个单元测试。我首先开始:

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


但是,这不会运行。

TypeError: 'property' object is not callable


接下来,将r = ClustererKmeans.clusters(sut)行更改为以下内容:

r = sut.clusters


但是,再次,我得到了一个意外错误。

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


有没有一种简单的方法可以使用unittest框架在Python中测试属性的实现?

最佳答案

要直接call property,您可以用ClustererKmeans.clusters(sut)替换原始代码ClustererKmeans.clusters.__get__(sut)

即使我是一个嘲笑热情的恕我直言,这种情况也不是应用它的好例子。模拟对于从类和资源中删除依赖项很有用。在您的情况下,ClustererKmeans有一个空的构造函数,没有任何要打破的依赖关系。您可以通过以下方式实现:

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)


如果要使用模拟,则可以使用ClustererKmeans()修补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)


...但是当python为您提供简单直接的方法时,为什么要使用patch?

使用模拟框架的另一种方法应该是信任numpy.unique并检查属性是否
正确的工作:

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


对于某些错误,我深表歉意,但是我没有测试代码。如果您通知我,我将尽快修复所有问题。

10-07 18:39