Question

IDE: PyCharm Community Edition 3.1.1
Python: 2.7.6

I using DDT for test parameterization http://ddt.readthedocs.org/en/latest/example.html

I want to choose and run parameterized test method from test class in PyCharm -> see example:

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)

When I navigate to the first test method test_print_value in code and hit ctrl+Shift+F10 (or use Run Unittest test_print... option from context menu) then test is executed.

When I try the same with parameterized test I get error:

Test framework quit unexpectedly

And output contains:

/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

However when I run all tests in class (by navigating to test class name in code and using mentioned run test option) all parameterized and non parameterized tests are executed together without errors.

The problem is how to independently run prameterized method from the test class - workaround is putting one parameterized test per test class but it is rather messy solution.

Was it helpful?

Solution

Actually this is issue in PyCharm utrunner.py who runs unittests. If you are using DDT there is a wrapper @ddt and @data - it is responsible for creating separate tests for each data entry. In the background these tests have different names e.g.

@ddt
class MyTestClass(unittest.TestCase):
    @data(1, 2)
    def test_print(self, command):
        print command

This would create tests named: - test_print_1_1 - test_print_2_2

When you try to run one test from the class (Right Click -> Run 'Unittest test_print') PyCharm has a problem to load your tests print_1_1, print_2_2 as it is trying to load test_print test.

When you look at the code of 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))

and you will debug it you see that issue.

Ok. So my fix for that is to load proper tests from the class. It is just a workaround and it is not perfect, however as DDT is adding a TestCase as another method to the class it is hard to find a different way to detect right test cases than comparing by string. So instead of:

try:
          all.addTest(testCaseClass(a[2]))

you can try to use:

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])))

Checking if digit is found after the main name is a workaround to exclude similar test cases:

  • test_print

  • test_print_another_case

But of course it would not exclude cases:

  • test_if_prints_1

  • test_if_prints_2

So in the worst case, if we haven't got a good name convention we will run similar tests, but in most cases it should just work for you.

OTHER TIPS

When I ran into this error, it was because I had implemented an init function as follows:

def __init__(self):
    super(ClassInheritingTestCase, self).__init__()

When I changed it to the following, it worked properly:

def __init__(self, *args, **kwargs):
    super(ClassInheritingTestCase, self).__init__(*args, **kwargs)

The problem was caused by me not propagating the *args and **kwargs through properly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top