20

I have a class for testing some of my code. I would like to parametrize the setup and rerun the class with different parameters:

class TestNormalLTEPlasma:


    def setup(self, t=10000):
        self.plasma = plasma.LTEPlasma.from_abundance(t, {'Si':1.0}, 1e-13, atom_data, 10*86400)

    def test_beta_rad(self):
        assert self.plasma.beta_rad == 1 / (10000 * constants.k_B.cgs.value)

    def test_t_electron(self):
        assert self.plasma.t_electron == 0.9 * self.plasma.t_rad

    def test_saha_calculation_method(self):
        assert self.plasma.calculate_saha == self.plasma.calculate_saha_lte

I would like to run this class going from t=2000 to t=20000 in steps of 1000.

lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
Wolfgang Kerzendorf
  • 724
  • 1
  • 9
  • 24
  • What have you tried? There are docs for [parametrized test functions](http://pytest.org/latest/parametrize.html#parametrized-test-functions) and for [fixtures](http://pytest.org/latest/fixture.html#fixture) that do just that. – Alex Okrushko Jul 03 '13 at 12:53
  • @WolfgangKerzendorf, I added an answer to your question. – lmiguelvargasf May 13 '19 at 17:31

2 Answers2

24

Instead of your setup function, create a parametrized test fixture:

ts = range(2000, 20001, 1000)  # This creates a list of numbers from 2000 to 20000 in increments of 1000.

@pytest.fixture(params=ts)
def plasma(request):
    return plasma.LTEPlasma.from_abundance(request.param, {'Si':1.0}, 1e-13, atom_data, 10*86400)

A "parametrized test fixture" is one where, when you use it in a test case, pytest will create a new test case for each parameter and run each separately.

You use the test fixture by adding a function argument called "plasma" to each of the test functions that want it:

class TestNormalLTEPlasma:

    def test_beta_rad(self, plasma):
        assert plasma.beta_rad == 1 / (10000 * constants.k_B.cgs.value)

    def test_t_electron(self, plasma):
        assert plasma.t_electron == 0.9 * plasma.t_rad

    def test_saha_calculation_method(self, plasma):
        assert plasma.calculate_saha == plasma.calculate_saha_lte

pytest takes care of collecting fixtures, collecting test functions, figuring out which test functions need which fixtures, and passing the fixture values to the test functions for execution.

Check out the docs for more details: https://docs.pytest.org/en/latest/fixture.html#fixture-parametrize

Jack Thomson
  • 450
  • 4
  • 9
Frank T
  • 8,268
  • 8
  • 50
  • 67
7

You can also apply parametrize your class, so the same data will be sent to all test methods in the class.

First, create a list plasmas that contains the plasma elements you want to pass to each test. Second, use the decorator @pytest.mark.parametrize, and pass plasmas to it.

plasmas = [plasma.LTEPlasma.from_abundance(t, {'Si':1.0}, 1e-13, atom_data, 10*86400) for t in range(2000, 20001, 1000)]

@pytest.mark.parametrize('plasma', plasmas)
class TestNormalLTEPlasma:
    def test_beta_rad(self, plasma):
        assert plasma.beta_rad == 1 / (10000 * constants.k_B.cgs.value)

    def test_t_electron(self, plasma):
        assert plasma.t_electron == 0.9 * plasma.t_rad

    def test_saha_calculation_method(self, plasma):
        assert plasma.calculate_saha == plasma.calculate_saha_lte
lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
  • 7
    Can one use class level parametrize decorator to pass parameter to __init__ method of unittest.TestCase class ? >@pytest.mark.parametrize('test_input', [1, 2, 3, 4]) class TestClass(unittest.TestCase): def __init__(self, method_name, test_input): super().__init__(method_name) self.test_input = test_input – Rohit.M May 20 '19 at 16:57