具有昂贵设置的 Python 单元测试
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/423483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python unittest with expensive setup
提问by Staale
My test file is basically:
我的测试文件基本上是:
class Test(unittest.TestCase):
def testOk():
pass
if __name__ == "__main__":
expensiveSetup()
try:
unittest.main()
finally:
cleanUp()
However, I do wish to run my test through Netbeans testing tools, and to do that I need unittests that don't rely on an environment setup done in main. Looking at Caching result of setUp() using Python unittest- it recommends using Nose. However, I don't think Netbeans supports this. I didn't find any information indicating that it does. Additionally, I am the only one here actually writing tests, so I don't want to introduce additional dependencies for the other 2 developers unless they are needed.
但是,我确实希望通过 Netbeans 测试工具运行我的测试,为此我需要不依赖于在main 中完成的环境设置的单元测试。纵观使用Python单元测试缓存安装程序的结果()-它建议使用鼻子。但是,我认为 Netbeans 不支持这一点。我没有找到任何信息表明它确实如此。此外,我是这里唯一一个实际编写测试的人,所以除非需要,否则我不想为其他 2 个开发人员引入额外的依赖项。
How can I do the setup and cleanup once for all the tests in my TestSuite?
如何为我的 TestSuite 中的所有测试进行一次设置和清理?
The expensive setup here is creating some files with dummy data, as well as setting up and tearing down a simple xml-rpc server. I also have 2 test classes, one testing locally and one testing all methods over xml-rpc.
这里昂贵的设置是创建一些带有虚拟数据的文件,以及设置和拆除一个简单的 xml-rpc 服务器。我也有 2 个测试类,一个在本地测试,一个在 xml-rpc 上测试所有方法。
回答by Mekk
If you use Python >= 2.7 (or unittest2for Python >= 2.4 & <= 2.6), the best approach would be be to use
如果您使用 Python >= 2.7(或unittest2for Python >= 2.4 & <= 2.6),最好的方法是使用
def setUpClass(cls):
# ...
setUpClass = classmethod(setUpClass)
to perform some initialization once for all tests belonging to the given class.
对属于给定类的所有测试执行一次初始化。
And to perform the cleanup, use:
并执行清理,使用:
@classmethod
def tearDownClass(cls):
# ...
See also the unittest standard library documentation on setUpClass and tearDownClass classmethods.
另请参阅有关 setUpClass 和 tearDownClass 类方法的 unittest 标准库文档。
回答by Tal Weiss
This is what I do:
这就是我所做的:
class TestSearch(unittest.TestCase):
"""General Search tests for...."""
matcher = None
counter = 0
num_of_tests = None
def setUp(self): # pylint: disable-msg=C0103
"""Only instantiate the matcher once"""
if self.matcher is None:
self.__class__.matcher = Matcher()
self.__class__.num_of_tests = len(filter(self.isTestMethod, dir(self)))
self.__class__.counter = self.counter + 1
def tearDown(self): # pylint: disable-msg=C0103
"""And kill it when done"""
if self.counter == self.num_of_tests:
print 'KILL KILL KILL'
del self.__class__.matcher
Sadly (because I do want my tests to be independent and deterministic), I do this a lot (because system testing that take less than 5 minutes are also important).
可悲的是(因为我确实希望我的测试是独立的和确定性的),我经常这样做(因为少于 5 分钟的系统测试也很重要)。
回答by user51568
First of all, what S. Lott said. However!, you do not want to do that. There is a reason setUp and tearDown are wrapped around each test: they help preserve the determinism of testing.
首先,S. Lott 所说的。但是!,您不想这样做。每个测试都包含 setUp 和 tearDown 是有原因的:它们有助于保持测试的确定性。
Otherwise, if some test places the system in a bad state, your next tests may fail. Ideally, each of your tests should be independent.
否则,如果某些测试使系统处于不良状态,您的下一个测试可能会失败。理想情况下,您的每个测试都应该是独立的。
Also, if you insist on doing it this way, instead of writing by hand self.runTest1(), self.runTest2(), you might want to do a bit of introspection in order to find the methods to run.
此外,如果您坚持这样做,而不是手动编写 self.runTest1()、self.runTest2(),您可能需要进行一些内省以找到要运行的方法。
回答by Brian Clapper
Won't package-level initialization do it for you? From the Nose Wiki:
包级初始化不会为你做吗?从鼻子维基:
nose allows tests to be grouped into test packages. This allows package-level setup; for instance, if you need to create a test database or other data fixture for your tests, you may create it in package setup and remove it in package teardown once per test run, rather than having to create and tear it down once per test module or test case.
To create package-level setup and teardown methods, define setup and/or teardown functions in the
__init__.py
of a test package. Setup methods may be namedsetup
,setup_package
,setUp
, orsetUpPackage
; teardown may be namedteardown
,teardown_package
,tearDown
ortearDownPackage
. Execution of tests in a test package begins as soon as the first test module is loaded from the test package.
鼻子允许将测试分组到测试包中。这允许包级设置;例如,如果您需要为您的测试创建一个测试数据库或其他数据固定装置,您可以在包设置中创建它并在每次测试运行时在包拆卸中将其删除,而不是每个测试模块都必须创建和拆卸一次或测试用例。
要创建包级设置和拆卸方法,请在
__init__.py
测试包的 中定义设置和/或拆卸功能。安装方法可能被命名为setup
,setup_package
,setUp
,或setUpPackage
; 拆卸可以命名为teardown
,teardown_package
,tearDown
或tearDownPackage
。一旦从测试包中加载第一个测试模块,就开始在测试包中执行测试。
回答by muhuk
You can save the state if expensiveSetup()
is run or not.
expensiveSetup()
无论是否运行,您都可以保存状态。
__expensiveSetup_has_run = False
class ExpensiveSetupMixin(unittest.TestCase):
def setUp(self):
global __expensiveSetup_has_run
super(ExpensiveSetupMixin, self).setUp()
if __expensiveSetup_has_run is False:
expensiveSetup()
__expensiveSetup_has_run = True
Or some kind of variation of this. Maybe pinging xml-rpc server and create a new one if it isn't answering.
或者这种变化的某种形式。也许 ping xml-rpc 服务器并创建一个新服务器,如果它没有响应。
But the unit-testing way AFAIK is to setup and teardown per unittesteven if it is expensive.
但是 AFAIK 的单元测试方式是设置和拆卸每个单元测试,即使它很昂贵。
回答by Lennart Regebro
I know nothing about Netbeans, but I though I should mention zope.testrunnerand it's support for a nifty thing: Layers. Basically, you do the testsetup in separate classes, and attach those classes to the tests. These classes can inherit from each other, forming a layer of setups. The testrunner will then only call each setup once, and saving the state of that in memory, and instead of setting up and tearing down, it will simply just copy the relevant layer context as a setup.
我对 Netbeans 一无所知,但我应该提到zope.testrunner,它支持一个漂亮的东西:层。基本上,您在单独的类中进行测试设置,并将这些类附加到测试中。这些类可以相互继承,形成一层设置。然后,测试运行器将只调用每个设置一次,并将其状态保存在内存中,而不是设置和拆除,它只是简单地复制相关层上下文作为设置。
This speeds up test setup a lot, and is used when you test Zope products and Plone, where the testsetup often needs you to start a Plone CMS server, create a Plone site and add loads of content, a process that can take upwards half a minute. Doing that for each test method is obviously impossible, but with layers it is done only once. This shortens the test setup andprotects the test methods from each other, and therefore means that the testing continues to be determenistic.
这大大加快了测试设置的速度,并且在您测试 Zope 产品和 Plone 时使用,其中测试设置通常需要您启动 Plone CMS 服务器、创建 Plone 站点并添加大量内容,这个过程可能需要超过一半的时间分钟。对每个测试方法都这样做显然是不可能的,但是对于层,它只完成一次。这缩短了测试设置并保护了测试方法之间的相互隔离,因此意味着测试继续是确定性的。
So I don't know of zope.testrunner will work for you, but it's worth a try.
所以我不知道 zope.testrunner 对你有用,但值得一试。
回答by S.Lott
You can assure setUp
and tearDown
execute once if you have only one test method, runTest
. This method can do whatever else it wants. Just be sure you don't have any methods with names that start with test
.
如果您只有一种测试方法,则可以保证setUp
并tearDown
执行一次runTest
。这种方法可以为所欲为。请确保您没有任何名称以test
.
class MyExpensiveTest( unittest.TestCase ):
def setUp( self ):
self.resource = owThatHurts()
def tearDown( self ):
self.resource.flush()
self.resource.finish()
def runTest( self ):
self.runTest1()
self.tunTest2()
def runTest1( self ):
self.assertEquals(...)
def runTest2( self ):
self.assertEquals(...)
It doesn't automagically figure out what to run. If you add a test method, you also have to update runTest.
它不会自动找出要运行的内容。如果添加测试方法,则还必须更新 runTest。