Python 单元测试:确保对象不包含来自先前 运行 的数据
Python Unittest: Ensure that objects do not contain data from previous run
我正在使用 setUp
从我创建的 class 创建一个新对象。据我了解,此函数将在测试用例中的每个测试之前执行,并且这应该导致为每个测试创建 new 对象。似乎这不是正在发生的事情;至少在我的测试中没有。
这是我的 class:
class Entity:
def __init__(self, entities = []):
self.entities = entities
def add(self, entity: str):
if entity not in self.entities:
self.entities.append(entity)
这里是相应的测试:
import unittest
from entity import Entity
class EntityTestCase(unittest.TestCase):
def setUp(self):
self.entity = Entity()
print("Starting Entites = {}".format(self.entity.entities))
def testA(self):
self.entity.add("Foo")
self.assertEqual(self.entity.entities, ["Foo"])
def testB(self):
self.entity.add("Bar")
self.assertEqual(self.entity.entities, ["Bar"])
if __name__ == '__main__':
unittest.main()
我希望 testA
和 testB
将从新的 Entity
对象开始。也就是说,我希望 Entity.entities
成为每个测试的全新列表。
我 运行 我的测试 python -m unittest discover -v
结果如下:
$ python -m unittest discover -v
testA (test_entity.EntityTestCase) ... Starting Entites = []
ok
testB (test_entity.EntityTestCase) ... Starting Entites = ['Foo']
FAIL
======================================================================
FAIL: testB (test_entity.EntityTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/julioguzman/Sites/Foobar/test_entity.py", line 15, in testB
self.assertEqual(self.entity.entities, ["Bar"])
AssertionError: Lists differ: ['Foo', 'Bar'] != ['Bar']
First differing element 0:
'Foo'
'Bar'
First list contains 1 additional elements.
First extra element 1:
'Bar'
- ['Foo', 'Bar']
+ ['Bar']
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
如您所见,testB
从 testA
的数据开始。这不是期望的行为,尽管它可能是预期的行为。
如何确保每次测试我的对象都是 "clean"?为什么会这样?
你有
class Entity:
def __init__(self, entities = []):
self.entities = entities
默认参数被实例化一次,从而导致这个常见问题
- "Least Astonishment" and the Mutable Default Argument
只需修改 __init__
以使用替代值并分配一个全新的列表:
class Entity:
def __init__(self, entities=NotImplemented):
if entities is NotImplemented:
self.entities = []
else:
self.entities = entities
顺便说一句,这是编写单元测试的原因之一:它们还测试 class 是否以预期的行为正确创建。当 setUp
清楚地表明它创建了一个全新的对象时,这不是您的测试的问题 - 错误在于它做了一些意外的实现。
我正在使用 setUp
从我创建的 class 创建一个新对象。据我了解,此函数将在测试用例中的每个测试之前执行,并且这应该导致为每个测试创建 new 对象。似乎这不是正在发生的事情;至少在我的测试中没有。
这是我的 class:
class Entity:
def __init__(self, entities = []):
self.entities = entities
def add(self, entity: str):
if entity not in self.entities:
self.entities.append(entity)
这里是相应的测试:
import unittest
from entity import Entity
class EntityTestCase(unittest.TestCase):
def setUp(self):
self.entity = Entity()
print("Starting Entites = {}".format(self.entity.entities))
def testA(self):
self.entity.add("Foo")
self.assertEqual(self.entity.entities, ["Foo"])
def testB(self):
self.entity.add("Bar")
self.assertEqual(self.entity.entities, ["Bar"])
if __name__ == '__main__':
unittest.main()
我希望 testA
和 testB
将从新的 Entity
对象开始。也就是说,我希望 Entity.entities
成为每个测试的全新列表。
我 运行 我的测试 python -m unittest discover -v
结果如下:
$ python -m unittest discover -v
testA (test_entity.EntityTestCase) ... Starting Entites = []
ok
testB (test_entity.EntityTestCase) ... Starting Entites = ['Foo']
FAIL
======================================================================
FAIL: testB (test_entity.EntityTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/julioguzman/Sites/Foobar/test_entity.py", line 15, in testB
self.assertEqual(self.entity.entities, ["Bar"])
AssertionError: Lists differ: ['Foo', 'Bar'] != ['Bar']
First differing element 0:
'Foo'
'Bar'
First list contains 1 additional elements.
First extra element 1:
'Bar'
- ['Foo', 'Bar']
+ ['Bar']
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
如您所见,testB
从 testA
的数据开始。这不是期望的行为,尽管它可能是预期的行为。
如何确保每次测试我的对象都是 "clean"?为什么会这样?
你有
class Entity:
def __init__(self, entities = []):
self.entities = entities
默认参数被实例化一次,从而导致这个常见问题
- "Least Astonishment" and the Mutable Default Argument
只需修改 __init__
以使用替代值并分配一个全新的列表:
class Entity:
def __init__(self, entities=NotImplemented):
if entities is NotImplemented:
self.entities = []
else:
self.entities = entities
顺便说一句,这是编写单元测试的原因之一:它们还测试 class 是否以预期的行为正确创建。当 setUp
清楚地表明它创建了一个全新的对象时,这不是您的测试的问题 - 错误在于它做了一些意外的实现。