编写可重用(参数化)的unittest.TestCase方法
可能的重复:
如何在 python 中生成动态(参数化)单元测试?
我正在使用 unittest 包编写测试,并且我想避免重复的代码。我将进行一系列测试,这些测试都需要非常相似的方法,但每次只有一个值不同。一个简单且无用的例子是:
class ExampleTestCase(unittest.TestCase):
def test_1(self):
self.assertEqual(self.somevalue, 1)
def test_2(self):
self.assertEqual(self.somevalue, 2)
def test_3(self):
self.assertEqual(self.somevalue, 3)
def test_4(self):
self.assertEqual(self.somevalue, 4)
有没有一种方法可以编写上面的示例,而不必每次都重复所有代码,而是编写一个通用方法,例如
def test_n(self, n):
self.assertEqual(self.somevalue, n)
并告诉 unittest 使用不同的输入尝试此测试?
Possible Duplicate:
How to generate dynamic (parametrized) unit tests in python?
I'm writing tests using the unittest package, and I want to avoid repeated code. I am going to carry out a number of tests which all require a very similar method, but with only one value different each time. A simplistic and useless example would be:
class ExampleTestCase(unittest.TestCase):
def test_1(self):
self.assertEqual(self.somevalue, 1)
def test_2(self):
self.assertEqual(self.somevalue, 2)
def test_3(self):
self.assertEqual(self.somevalue, 3)
def test_4(self):
self.assertEqual(self.somevalue, 4)
Is there a way to write the above example without repeating all the code each time, but instead writing a generic method, e.g.
def test_n(self, n):
self.assertEqual(self.somevalue, n)
and telling unittest to try this test with different inputs?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
可用于在 Python 中进行参数化测试的一些工具包括:
Some of the tools available for doing parametrized tests in Python are:
如果你真的想要多个单元测试,那么你需要多种方法。实现这一点的唯一方法是通过某种代码生成。您可以通过元类或在定义后调整类来做到这一点,包括(如果您使用的是 Python 2.6)通过类装饰器。
这是一个解决方案,它查找特殊的“multitest”和“multitest_values”成员,并使用它们来动态构建测试方法。不优雅,但它大致达到了您想要的效果:
这是我运行它时的输出
您可以立即看到代码生成时出现的一些问题。 “test_gt_1”来自哪里?我可以将名称更改为更长的“test_multitest_gt_1”,但哪个测试是 1?最好从 _0 而不是 _1 开始,也许在您的情况下您知道这些值可以用作 Python 函数名称。
我不喜欢这种方法。我研究过自动生成测试方法的代码库(在一种情况下使用元类),发现它比有用的更难理解。当测试失败时,很难找出失败案例的根源,也很难坚持调试代码来探究失败的原因。
(我在这里编写的示例中的调试失败并不像我必须使用的特定元类方法那么难。)
If you really want to have multiple unitttest then you need multiple methods. The only way to get that is through some sort of code generation. You can do that through a metaclasses, or by tweaking the class after the definition, including (if you are using Python 2.6) through a class decorator.
Here's a solution which looks for the special 'multitest' and 'multitest_values' members and uses those to build the test methods on the fly. Not elegant, but it does roughly what you want:
This is the output from when I run it
You can immediately see some of the problems which occur with code generation. Where does "test_gt_1" come from? I could change the name to the longer "test_multitest_gt_1" but then which test is 1? Better here would be to start from _0 instead of _1, and perhaps in your case you know the values can be used as a Python function name.
I do not like this approach. I've worked on code bases which autogenerated test methods (in one case using a metaclass) and found it was much harder to understand than it was useful. When a test failed it was hard to figure out the source of the failure case, and it was hard to stick in debugging code to probe the reason for the failure.
(Debugging failures in the example I wrote here isn't as hard as that specific metaclass approach I had to work with.)
我猜你想要的是“参数化测试”。
我不认为unittest模块支持这个(不幸的是),
但如果我添加此功能,它看起来会像这样:
使用现有的unittest模块,像这样的简单装饰器将无法多次“复制”测试,但我认为使用以下组合是可行的装饰器和元类(元类应该观察所有“test*”方法并复制(在不同的自动生成的名称下)应用了装饰器的方法)。
I guess what you want is "parameterized tests".
I don't think unittest module supports this (unfortunately),
but if I were adding this feature it would look something like this:
With the existing unittest module, a simple decorator like this won't be able to "replicate" the test multiple times, but I think this is doable using a combination of a decorator and a metaclass (metaclass should observe all 'test*' methods and replicate (under different auto-generated names) those that have a decorator applied).
一种更加以数据为导向的方法可能比 Andrew Dalke 的 答案:
我不确定在确定顺序时涉及什么巫毒运行测试,但至少对我来说,文档测试始终通过。
对于更复杂的情况,可以将
cases
字典的values
元素替换为包含参数列表和关键字参数字典的元组。虽然那时你基本上是在用 python 编写 lisp 代码。A more data-oriented approach might be clearer than the one used in Andrew Dalke's answer:
I'm not sure what voodoo is involved in determining the order in which the tests are run, but the doctest passes consistently for me, at least.
For more complex situations it's possible to replace the
values
element of thecases
dictionaries with a tuple containing a list of arguments and a dict of keyword arguments. Though at that point you're basically coding lisp in python.编写一个执行所有测试并捕获所有结果的测试方法,将您自己的诊断消息写入 stderr,并在其任何子测试失败时使测试失败:
当然请注意
my_test()
的名称不能以test
开头。Write a single test method that performs all of your tests and captures all of the results, write your own diagnostic messages to stderr, and fail the test if any of its subtests fail:
Note that of course
my_test()
's name can't begin withtest
.也许是这样的:
Perhaps something like: