【问题标题】:Unittest implementation Python property单元测试实现 Python 属性
【发布时间】:2015-03-03 06:17:00
【问题描述】:

我有一个具有以下属性的课程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 中测试属性的实现?

【问题讨论】:

  • 你不应该做r = sut.clusters吗? self 参数默认发送。我看到另一个问题sut.clustering 不是初始化类变量的正确方法。您应该在初始化类时将其作为参数发送
  • 我确实尝试过r = sut.clusters,但在上面的代码中,它返回一个 Mock 对象,而不是一个 numpy 数组。

标签: python properties unit-testing


【解决方案1】:

直接到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)

如果您要使用模拟,您可以使用 unittest.mock.patch.object 修补 ClustererKmeans() 对象:

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)

我为一些错误道歉,但我不测试代码。如果您通知我,我会尽快解决所有问题。

【讨论】:

  • 我在阅读 stackoverflow.com/a/14921351/4101725stackoverflow.com/a/14249723/4101725 后修复了 np.array 的测试
  • r = ClustererKmeans.clusters(__get__(sut)) 行给了我一个错误:NameError: name '__get__' is not defined。构造函数在这里是空的,因为我在我的问题中遗漏了所有不相关的细节。在实践中,代码更加精细。
  • r = ClustererKmeans.clusters.__get__(sut) 行确实按预期工作。感谢您指出这一点!
猜你喜欢
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-05
相关资源
最近更新 更多