Skip to main content
 首页 » 编程设计

python之nosetest 的奇怪行为

2025年05月04日18jiqing9006

我尝试用 Nose 测试 但是当我运行下面的测试用例时

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_2,setUp 运行并且 self.b 是 [10, 20]。

但实际上,在 setUp 处 self.b 的值是 [10, 20, 30]。

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

有什么相关的提示吗? 我仍然没有弄明白,但我找到了修复这个错误的方法。只需将 self.b = [] 更改为 del self.b[:]。

谁能帮我找出问题所在? 非常感谢。

请您参考如下方法:

据我所知,问题可能与 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 多次创建对象,为每个测试函数创建对象,触发访问类变量的设置,测试运行,调用简单隐藏它的拆解,创建另一个对象,调用访问相同的设置前一个对象修改的类变量,自从它被拆除后就没有影响,它只是创建了一个绑定(bind)到自身的新实例,隐藏了类版本。

我们总是使用 self 在 __init__ 中声明成员字段。

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]