我尝试使用鼻子测试 但是当我运行下面的测试用例时
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 is [10, 20, 30]
。
我不知道为什么。我认为陈述self.b = []
必定存在一些问题。
我猜是否有任何相关指针?
我仍然没弄清楚,但我找到了解决这个问题的方法。只需将self.b = []
更改为del self.b[:]
。
任何人都可以帮我找出问题所在? 非常感谢你。
答案 0 :(得分: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,创建另一个对象,调用访问它的设置上一个对象修改后的类变量,因为它的拆除只是创建了一个绑定到self的新实例,隐藏了类版本。
我们总是使用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]
答案 1 :(得分:2)
问题是第2行中的class属性:
b = []
这是类TestSuite
的属性。 Nosetests创建类TestSuite
的新实例,然后调用setUp
。在setUp
中,您修改了课程TestSuite
上的类属性:
self.b.extend([10, 20])
然后,在tearDown
中,在运行第一个测试后,您创建一个新列表并将其分配给新的实例属性,该属性也恰好称为{{1 }}:
b
这根本不会修改类属性。进一步尝试从此实例访问self.b = []
将返回实例属性,而不是类属性。
但这没有任何效果,因为接下来发生的事情是,nosetests会抛弃self.b
的当前实例,包括实例属性中的新空列表{{您在TestSuite
中设置的1}}。
然后,nosetests会创建一个全新的类b
实例,以进行第二次测试。但是,课程tearDown
仍然包含TestSuite
类属性,其中包含TestSuite
,因为它在您的第一次测试运行时已被修改。
然后运行nosetests b
方法,将[10, 20, 30]
和setUp
添加到10
的类属性20
。然后你的第二个测试运行,将TestSuite
添加到b
的类属性,你的第二个测试失败,因为它在类中找到六个项目>属性:
40
TestSuite
有效的原因是,就像[10,20,30,10,20,40]
一样,del self.b[:]
正在修改类属性,而不是创建新的实例属性。
确保你理解类和实例之间的区别,以及类属性和实例属性之间的区别,否则只要你使用Python就会遇到类似的问题。
答案 2 :(得分:0)
好吧,尝试替换:
self.b.extend([10,20])
与
self.b = [10,20]
并且可能抛出类变量,你不需要它,这可能是发生这种情况的原因。