1

我尝试使用鼻子测试但是当我运行下面的测试用例时

import unittest

class TestSuite(unittest.TestCase):
    b = []

    def setUp(self):
        self.b.extend([10, 20])

    def tearDown(self):
        self.b = []

    def test_case_1(self):
        self.b.append(30)
        assert len(self.b) == 3
        assert self.b == [10, 20, 30]

    def test_case_2(self):
        self.b.append(40)
        assert len(self.b) == 3
        assert self.b == [10, 20, 40]

但是所有测试用例都没有通过

$> nosetest test_module.py
.F
======================================================================
FAIL: test_case_2 (test_module2.TestSuite)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/knt/test_module2.py", line 19, in test_case_2
    assert len(self.b) == 3
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

发生了什么 ???我希望在运行 test_case_1 之后,会调用 tearDown ,self.b所以[]. 所以对于下一个测试用例test_case_2setUp运行并且self.b[10, 20]

但实际上,setUpself.b is [10, 20, 30].

我不知道为什么。我认为 statement 一定有一些问题self.b = []

有什么相关的指针,我猜?我仍然没有弄清楚,但我找到了修复这个错误的方法。只需更改self.b = []del self.b[:].

任何人都可以帮我找出问题吗?太感谢了。

4

3 回答 3

4

据我所知,问题可能与 unitests 的工作方式以及类字段在 python 中的工作方式有关,这是一个简单的测试:

class A:
    b = []
    def reset(self):
        self.b = []

a = A()    
a.b.append(3) # we are actually accessing the class variable here
print A.b is a.b # True
print a.b # [3] same here
a.reset() # We just hid the class variable with our own which points to []
print A.b is a.b # False as expected.
print a.b # [] we think its being clear but rather we are using our own not the class variable

b = A()
print b.b # [3] b here is using the class that a previously modified but is no longer pointing to
print b.b is A.b # True

# Also note
c = A()
d = A()
print c.b is d.b # True, since both are using the same class variable.

我认为unittest多次创建对象,对于每个测试函数,创建对象,触发访问类变量的设置,测试运行,调用简单隐藏它的teardown,创建另一个对象,调用访问相同类变量的设置先前的对象已修改并且没有影响,因为它的拆除只是创建了一个绑定到自身的新实例,隐藏了类版本。

我们总是在__init__using self 中声明成员字段。

def __init__(self):
    self.b = []

这样每个实例都会有自己的副本,尽管我们不能在这里这样做,因为我们是从那里继承的,unittest.TestCase这就是我们拥有的原因setUp

import unittest
class TestSuite(unittest.TestCase):
    def setUp(self):
        self.b = [10, 20]

    def tearDown(self):
        self.b = []

    def test_case_1(self):
        self.b.append(30)
        assert len(self.b) == 3
        assert self.b == [10, 20, 30]

    def test_case_2(self):
        self.b.append(40)
        assert len(self.b) == 3
        assert self.b == [10, 20, 40]
于 2012-06-16T09:03:28.383 回答
2

问题是您在第 2 行中的类属性:

b = []

那是类的一个属性TestSuite。Nosetests 创建一个新的类实例TestSuite,然后调用setUp. 在setUp中,您修改类的属性TestSuite

self.b.extend([10, 20])

然后,在tearDown运行第一个测试之后,创建一个新列表并将其分配给一个新的实例属性,该属性也恰好被调用b

self.b = []

这根本不会修改属性。进一步尝试self.b从此实例进行访问将返回实例属性,而不是类属性。

但这没有任何效果,因为接下来发生的事情是,nosetests 会丢弃 的当前实例,包括您在 中设置的实例属性TestSuite中的新空列表。btearDown

然后 nosetests 创建一个全新的 class 实例TestSuite,来运行你的第二个测试。但是该类TestSuite仍然有一个包含 的b 属性[10, 20, 30],因为它在您的第一个测试运行时被修改了。

然后nosetestssetUp方法运行,添加1020TestSuite属性b。然后您的第二个测试运行,添加40TestSuiteclass属性,并且您的第二个测试失败,因为它在该class属性中找到六个项目:

[10,20,30,10,20,40]

起作用的原因del self.b[:]是,就像 一样appenddel正在修改属性,而不是创建新的实例属性。

确保你了解类和实例之间、类属性和实例属性之间的区别,否则只要你在使用 Python,就会被类​​似的问题所困扰。

于 2012-06-16T11:13:36.323 回答
0

好吧,尝试替换:

self.b.extend([10,20])

self.b = [10,20]

也许扔掉类变量,你不需要它,这可能是发生这种情况的原因。

于 2012-06-16T08:41:37.760 回答