Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Py.test: parametrize test cases from classes

I'm currently following this py.test example and it works out when I do not use classes, however when I introduce test cases into classes I am failing.

The smallest case I managed to write is the following:

import unittest  import pytest  class FixtureTestCase(unittest.TestCase):      @pytest.mark.parametrize("test_input,expected", [     ("3+5", 8),     ("2+4", 6),     ("6*9", 42),     ])     def test_1(self, a, b):         self.assertEqual(a, b) 

unfortunately when I execute

  py.test  test_suite.py 

I get the error message:

  TypeError: test_1() takes exactly 3 arguments (1 given) 

How can I do in order to generate a battery of test_1 tests?

like image 346
pafede2 Avatar asked Feb 22 '16 19:02

pafede2


People also ask

How does pytest Mark Parametrize work?

mark. parametrize : parametrizing test functions. Parameter values are passed as-is to tests (no copy whatsoever). For example, if you pass a list or a dict as a parameter value, and the test case code mutates it, the mutations will be reflected in subsequent test case calls.

Can we use fixture in Parametrize pytest?

Being able to reuse fixtures in parametrized tests is a must when we want to avoid repetition. Unfortunately, pytest doesn't support that yet. On the other hand, we can make it happen either by using getfixturevalue in pytest or through a third-party library.

How do you run the same test multiple times in pytest?

Repeating a test Each test collected by pytest will be run count times. If you want to override default tests executions order, you can use --repeat-scope command line option with one of the next values: session , module , class or function (default). It behaves like a scope of the pytest fixture.


2 Answers

If you subclass from unittest.TestCase, your test methods cannot have additional arguments. If you simply subclass from object, it will work (though you'll have to use regular assert statements instead of the TestCase.assertEqual methods.

import unittest  import pytest  class TestCase(object):      @pytest.mark.parametrize("test_input,expected", [     ("3+5", 8),     ("2+4", 6),     ("6*9", 42),     ])     def test_1(self, a, b):         assert eval(a) == b 

At that point though, it kind of begs the question why you're using classes instead of just defining functions, since the test will essentially be the same, but require less overall boilerplate and code.

like image 161
Brendan Abel Avatar answered Sep 20 '22 14:09

Brendan Abel


I don't know if this was the case 5 years ago, but these days you can use parameterized (https://pypi.org/project/parameterized/) with pytest to decorate test methods on a test class, yes including unittest.TestCase, without having to resort to nose. E.g.:

from unittest import TestCase from parameterized import parameterized  class SomeTestCase(TestCase):      @parameterized.expand([         (1, 2),         ('a', 'b')     ])     def test_something(self, param1, param2):         ... 

The only gotcha, but you better remember this, is that the decorator will generate new test methods for each listed input parameter, so you will not be able to run your original test method directly by specifying it on the command line. E.g. pytest some_test.py::SomeTestCase::test_something won't work anymore (because your test method now expects two parameters). However, you can call the generated methods directly, for which you can get the name from either the pytest error output when you run the whole TestCase or by doing a pytest --collect-only.

like image 38
atleta Avatar answered Sep 19 '22 14:09

atleta