Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when running Python parameterized test method

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.

like image 429
pbaranski Avatar asked May 10 '14 09:05

pbaranski


People also ask

How do you check if a method throws an exception Python?

There are two ways you can use assertRaises: using keyword arguments. Just pass the exception, the callable function and the parameters of the callable function as keyword arguments that will elicit the exception. Make a function call that should raise the exception with a context.

How do you handle exceptions in unit test Python?

Test that an exception (first argument) is raised when a function is called with any positional or keyword arguments. The test passes if the expected exception is raised, is an error if another exception is raised, or fails if no exception is raised.

Is Pytest better than Unittest?

Which is better – pytest or unittest? Although both the frameworks are great for performing testing in python, pytest is easier to work with. The code in pytest is simple, compact, and efficient. For unittest, we will have to import modules, create a class and define the testing functions within that class.

What is parameterized expand?

And @parameterized.expand can be used to generate test methods in situations where test generators cannot be used (for example, when the test class is a subclass of unittest.TestCase): import unittest from parameterized import parameterized class AddTestCase(unittest. TestCase): @parameterized.


2 Answers

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.

like image 98
decu Avatar answered Sep 28 '22 22:09

decu


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.

like image 30
Dale Bruce Hopkins Avatar answered Sep 28 '22 21:09

Dale Bruce Hopkins