nmb*_*ten 43 python unit-testing
我如何确定unittest方法的顺序?字母或数字前缀是否正确?
class TestFoo(TestCase):
def test_1(self):
...
def test_2(self):
...
Run Code Online (Sandbox Code Playgroud)
要么
class TestFoo(TestCase):
def test_a(self):
...
def test_b(self):
...
Run Code Online (Sandbox Code Playgroud)
小智 73
没有理由认为你不能在之前的测试中进行构建,或者应该从头开始重建它以进行下一次测试.至少通常没有理由,但人们只是自信地说"你不应该".这没有用.
总的来说,我厌倦了在这里阅读太多的答案,基本上说"你不应该这样做"而不是提供任何关于如何最好地做到这一点的信息,如果在提问者的判断中有充分理由这样做的话.如果我想要某人就我是否应该做某事发表意见,那么我会就这是否是一个好主意征求意见.
除此之外,如果您阅读说loadTestsFromTestCase及其调用的内容,最终会以类方法字典中遇到的任何顺序扫描具有某种名称模式的方法,因此基本上按键顺序.它接受这些信息并制作一个测试套件,将其映射到TestCase类.给它一个按照你想要的顺序排列是一种方法来做到这一点.我不太确定最有效/最干净的方法,但这确实有效.
max*_*max 68
您可以通过将sortTestMethodsUsing设置为None来禁用它:http://docs.python.org/2/library/unittest.html#unittest.TestLoader.sortTestMethodsUsing
对于纯粹的单元测试,你们是对的; 但是对于组件测试和集成测试......我不同意你对状态一无所知.如果您正在测试州,该怎么办?例如,您的测试验证服务是否在安装时自动启动.如果在您的设置中,您启动服务,然后执行断言,那么您不再测试状态,而是在测试"服务启动"功能.
另一个例子是当您的设置需要很长时间或需要大量空间时,经常运行设置变得不切实际.
许多开发人员倾向于使用"unittest"框架进行组件测试......所以停下来问自己,我是在进行单元测试还是组件测试.
zou*_*oul 12
为什么需要特定的测试订单?测试应该是隔离的,因此应该可以以任何顺序运行它们,甚至可以并行运行它们.
如果您需要测试用户取消订阅之类的内容,则测试可以创建带有测试订阅的新数据库,然后尝试取消订阅.这种情况有其自身的问题,但最终它比测试依赖于彼此更好.(请注意,您可以分解常见的测试代码,这样您就不必重复数据库设置代码或创建令人作呕的测试数据.)
Elm*_*der 12
如果您使用'nose'并将测试用例编写为函数(而不是某些TestCase派生类的方法),则'nose'不会调整顺序,而是使用文件中定义的函数顺序.为了使assert_*方法更方便而不需要子类TestCase,我通常使用numpy中的测试模块.例:
from numpy.testing import *
def test_aaa():
assert_equal(1, 1)
def test_zzz():
assert_equal(1, 1)
def test_bbb():
assert_equal(1, 1)
Run Code Online (Sandbox Code Playgroud)
用''nosetest -vv''运行它给出:
test_it.test_aaa ... ok
test_it.test_zzz ... ok
test_it.test_bbb ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.050s
OK
Run Code Online (Sandbox Code Playgroud)
请注意所有那些认为不应该对单元测试进行排序的人:虽然单元测试应该是独立的并且可以独立运行,但是你的函数和类通常不是独立的.他们宁愿建立另一个从更简单/更低级别的功能到更复杂/更高级别的功能.当你开始优化低级功能并搞砸时(就我而言,我经常这样做;如果你不这样做,你可能不需要进行单元测试;-)那么它对于诊断原因来说要好得多,当简单函数的测试首先出现时,测试依赖于这些函数的函数.如果测试按字母顺序排序,真正的原因通常会在100个失败的断言中被淹没,这些断言不存在,因为测试中的函数有错误,但是因为它所依赖的低级函数具有错误.
这就是为什么我希望按照我指定的方式对单元测试进行排序:不使用在以后的测试中在早期测试中构建的状态,而是作为诊断问题的非常有用的工具.
我半同意不能订购测试的想法.在某些情况下,它有助于(它更容易该死!)将它们按顺序排列......毕竟这就是UnitTest中"单位"的原因.
这就是说一种替代方法是使用模拟对象来模拟和修补应该在测试的特定代码之前运行的项目.您还可以在其中放置一个虚拟函数来修补代码.有关更多信息,请查看Mock,它现在是标准库的一部分. 嘲笑
如果您之前没有使用过Mock,那么这里有一些YouTube视频.
更重要的是,尝试使用类方法来构造代码,然后将所有类方法放在一个主要的测试方法中.
import unittest
import sqlite3
class MyOrderedTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.create_db()
cls.setup_draft()
cls.draft_one()
cls.draft_two()
cls.draft_three()
@classmethod
def create_db(cls):
cls.conn = sqlite3.connect(":memory:")
@classmethod
def setup_draft(cls):
cls.conn.execute("CREATE TABLE players ('draftid' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 'first', 'last')")
@classmethod
def draft_one(cls):
player = ("Hakeem", "Olajuwon")
cls.conn.execute("INSERT INTO players (first, last) VALUES (?, ?)", player)
@classmethod
def draft_two(cls):
player = ("Sam", "Bowie")
cls.conn.execute("INSERT INTO players (first, last) VALUES (?, ?)", player)
@classmethod
def draft_three(cls):
player = ("Michael", "Jordan")
cls.conn.execute("INSERT INTO players (first, last) VALUES (?, ?)", player)
def test_unordered_one(self):
cur = self.conn.execute("SELECT * from players")
draft = [(1, u'Hakeem', u'Olajuwon'), (2, u'Sam', u'Bowie'), (3, u'Michael', u'Jordan')]
query = cur.fetchall()
print query
self.assertListEqual(query, draft)
def test_unordered_two(self):
cur = self.conn.execute("SELECT first, last FROM players WHERE draftid=3")
result = cur.fetchone()
third = " ".join(result)
print third
self.assertEqual(third, "Michael Jordan")
Run Code Online (Sandbox Code Playgroud)
排序“单元测试”测试的一个简单方法是遵循init.d机制,为它们提供数字名称:
def test_00_createEmptyObject(self):
obj = MyObject()
self.assertIsEqual(obj.property1, 0)
self.assertIsEqual(obj.dict1, {})
def test_01_createObject(self):
obj = MyObject(property1="hello", dict1={"pizza":"pepperoni"})
self.assertIsEqual(obj.property1, "hello")
self.assertIsDictEqual(obj.dict1, {"pizza":"pepperoni"})
def test_10_reverseProperty(self):
obj = MyObject(property1="world")
obj.reverseProperty1()
self.assertIsEqual(obj.property1, "dlrow")
Run Code Online (Sandbox Code Playgroud)
但是,在这种情况下,您可能需要考虑以不同的方式构建测试,以便可以在以前的构造案例的基础上进行构建。例如,在上面,使用“构造和验证”函数来构造对象并验证其参数分配可能是有意义的。
def make_myobject(self, property1, dict1): # Must be specified by caller
obj = MyObject(property1=property1, dict1=dict1)
if property1:
self.assertEqual(obj.property1, property1)
else:
self.assertEqual(obj.property1, 0)
if dict1:
self.assertDictEqual(obj.dict1, dict1)
else:
self.assertEqual(obj.dict1, {})
return obj
def test_00_createEmptyObject(self):
obj = self.make_object(None, None)
def test_01_createObject(self):
obj = self.make_object("hello", {"pizza":"pepperoni"})
def test_10_reverseProperty(self):
obj = self.make_object("world", None)
obj.reverseProperty()
self.assertEqual(obj.property1, "dlrow")
Run Code Online (Sandbox Code Playgroud)
小智 7
不要依赖订单.如果他们使用某些常见状态(如文件系统或数据库),那么您应该创建setUp和tearDown使您的环境进入可测试状态的方法,然后在测试运行后进行清理.每个测试都应该假设环境是如此定义的setUp,并且不应该做出进一步的假设.
小智 7
这是一种更简单的方法,具有以下优点:
这个想法是遍历提供给测试加载器协议的测试套件的所有测试用例并创建一个新套件,但测试按行号排序。
这是代码:
import unittest
def load_ordered_tests(loader, standard_tests, pattern):
"""
Test loader that keeps the tests in the order they were declared in the class.
"""
ordered_cases = []
for test_suite in standard_tests:
ordered = []
for test_case in test_suite:
test_case_type = type(test_case)
method_name = test_case._testMethodName
testMethod = getattr(test_case, method_name)
line = testMethod.__code__.co_firstlineno
ordered.append( (line, test_case_type, method_name) )
ordered.sort()
for line, case_type, name in ordered:
ordered_cases.append(case_type(name))
return unittest.TestSuite(ordered_cases)
Run Code Online (Sandbox Code Playgroud)
您可以将其放入名为 order_tests 的模块中,然后在每个单元测试 Python 文件中,声明测试加载器,如下所示:
from order_tests import load_ordered_tests
# This orders the tests to be run in the order they were declared.
# It uses the unittest load_tests protocol.
load_tests = load_ordered_tests
Run Code Online (Sandbox Code Playgroud)
注意:经常建议的将测试排序器设置为 None 的技术不再有效,因为 Python 现在对 dir() 的输出进行排序,而 unittest 使用 dir() 来查找测试。所以即使你没有排序方法,它们仍然会被Python本身排序!
优先考虑测试的原因有很多,其中最重要的是生产力,这正是JUnit Max的目标.在自己的模块中保持非常慢的测试有时很有帮助,这样您就可以从那些没有遭受相同重度依赖性的测试中获得快速反馈.排序也有助于跟踪非完全自包含的测试中的故障.
请注意,运行各种测试用例的顺序是通过根据字符串的内置顺序对测试函数名称进行排序来确定的。
如果您需要明确设置顺序,请使用整体测试。
class Monolithic(TestCase):
def step1(self):
...
def step2(self):
...
def steps(self):
for name in sorted(dir(self)):
if name.startswith("step"):
yield name, getattr(self, name)
def test_steps(self):
for name, step in self.steps():
try:
step()
except Exception as e:
self.fail("{} failed ({}: {})".format(step, type(e), e)
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请查看此堆栈溢出问题。
在某些情况下,顺序可能很重要,而 setUp 和 Teardown 的作用又太有限。只有一种 setUp 和tearDown 方法,这是合乎逻辑的,但是您只能在其中放入如此多的信息,直到不清楚setUp 或tearDown 实际在做什么为止。
以本次集成测试为例:
您正在编写测试来查看注册表单和登录表单是否正常工作。在这种情况下,顺序很重要,因为没有现有帐户就无法登录。更重要的是,测试的顺序代表某种用户交互。每个测试可能代表您正在测试的整个过程或流程中的一个步骤。
将代码划分为这些逻辑部分有几个优点。
这可能不是最好的解决方案,但我经常使用一种方法来启动实际测试:
def test_registration_login_flow(self):
_test_registration_flow()
_test_login_flow()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
51299 次 |
| 最近记录: |