IDE: PyCharm Community Edition 3.1.1
Python: 2.7.6
I使用DDT进行测试参数化http://ddt.readthedocs.org/en/latest/example.html
我想从PyCharm ->中的测试类中选择并运行参数化测试方法,参见示例:
from unittest import TestCase
from ddt import ddt, data
@ddt
class Test_parameterized(TestCase):
def test_print_value(self):
print 10
self.assertIsNotNone(10)
@data(10, 20, 30, 40)
def test_print_value_parametrized(self, value):
print value
self.assertIsNotNone(value)
当我在代码中导航到第一个测试方法test_print_value
并按ctrl+Shift+F10(或从上下文菜单中使用Run Unittest test_print...
选项)然后执行test。
当我尝试同样的参数化测试时,我得到错误:
Test framework quit unexpectedly
输出包含:
/usr/bin/python2 /home/s/App/pycharm-community-3.1.1/helpers/pycharm/utrunner.py
/home/s/Documents/Py/first/fib/test_parametrized.py::Test_parameterized::test_print_value_parametrized true
Testing started at 10:35 AM ...
Traceback (most recent call last):
File "/home/s/App/pycharm-community-3.1.1/helpers/pycharm/utrunner.py", line 148, in <module>
testLoader.makeTest(getattr(testCaseClass, a[2]), testCaseClass))
AttributeError: 'TestLoader' object has no attribute 'makeTest'
Process finished with exit code 1
然而,当我运行类中的所有测试时(通过导航到代码中的测试类名称并使用提到的运行测试选项),所有参数化和非参数化测试都被一起执行,没有错误。
问题是如何从测试类独立运行参数化方法-解决方法是为每个测试类放置一个参数化测试,但这是相当混乱的解决方案。
实际上这是PyCharm utrunner.py中运行单元测试的问题。如果使用DDT,则有一个包装器@ddt和@data——它负责为每个数据条目创建单独的测试。在后台,这些测试有不同的名称,例如
@ddt
class MyTestClass(unittest.TestCase):
@data(1, 2)
def test_print(self, command):
print command
这将创建名为:——test_print_1_1——test_print_2_2
当你尝试从类中运行一个测试时(右键单击->运行'Unittest test_print') PyCharm有一个问题来加载你的测试print_1_1, print_2_2,因为它试图加载test_print测试。
查看utrunner.py的代码:
if a[1] == "":
# test function, not method
all.addTest(testLoader.makeTest(getattr(module, a[2])))
else:
testCaseClass = getattr(module, a[1])
try:
all.addTest(testCaseClass(a[2]))
except:
# class is not a testcase inheritor
all.addTest(
testLoader.makeTest(getattr(testCaseClass, a[2]), testCaseClass))
你将调试它,如果你看到这个问题
Ok。我的解决办法是从类中加载适当的测试。这只是一个变通方法,它并不完美,然而,由于DDT将TestCase作为另一种方法添加到类中,很难找到一种不同的方法来检测正确的测试用例,而不是通过字符串进行比较。所以不是:
try:
all.addTest(testCaseClass(a[2]))
你可以尝试使用:
try:
all_tests = testLoader.getTestCaseNames(getattr(module, a[1]))
for test in all_tests:
if test.startswith(a[2]):
if test.split(a[2])[1][1].isdigit():
all.addTest(testLoader.loadTestsFromName(test, getattr(module,a[1])))
检查是否在主名之后找到数字是排除类似测试用例的解决方案:
test_print
test_print_another_case
当然也不排除这种情况:
test_if_prints_1
test_if_prints_2
所以在最坏的情况下,如果我们没有一个好的命名约定,我们将运行类似的测试,但在大多数情况下,它应该为您工作。
当我遇到这个错误时,这是因为我已经实现了init函数如下:
def __init__(self):
super(ClassInheritingTestCase, self).__init__()
当我将其更改为以下内容时,它正常工作:
def __init__(self, *args, **kwargs):
super(ClassInheritingTestCase, self).__init__(*args, **kwargs)
问题是由于我没有正确地传播*args和**kwargs。