Search code examples
pytestfixtures

Problem with unsollicited change of value for pytest fixture


I'm new to pytest and I can't solve an annoying problem. I want to have a fixture with base test values from a dataclass. And for certain test functions, I want to to modify some of these values locally to test some specificities. But I want to keep the base values unaltered for the next test functions !

Here's my code:

import pytest
from dataclasses import dataclass

@dataclass
class Def_Input:
    var1 = 3
    var2 = 4
    
@pytest.fixture
def def_inp():
    def_inp = Def_Input()
    return def_inp

def test_1(def_inp):
    temp = def_inp
    temp.var1 = 5
    assert def_inp.var1 == 3
    assert temp.var1 + temp.var2 == 9

The 2nd assert is not a problem, but the first one is. I get an AssertionError saying def_inp.var1 = 5 when I didn't modify def_inp, I used a temporary variable...

Would you have any ideas at to solve this?

Edit: @Steven97102 this does work for the example I gave, but I work on a slightly more complex function. In the dataclass, I create objects from external classes. It's something like this:

import pytest
import dataclasses
from dataclasses import dataclass

class Tab:
    def __init__(self, name):
        self.name = name

@dataclass
class Def_Input:
    var1 = 3
    var2 = 4
    name = 'paul'
    tab = Tab(name)
    
@pytest.fixture
def def_inp():
    def_inp = Def_Input()
    return def_inp

def test_1(def_inp):
    temp = dataclasses.replace(def_inp)
    temp.var1 = 5
    temp.tab.name = 'john'
    assert def_inp.tab.name == 'paul'
    assert def_inp.var1 == 3
    assert temp.var1 + temp.var2 == 9

Would you know I could get the first assert to work?


Solution

  • Python passes class instances using the reference model. This means that temp = def_inp simply creates a variable temp that points to the same object as def_inp. To avoid modifying the existing instance, you will have to create a new instance of it.

    Here's a solution that makes a deep copy of def_inp:

    import pytest
    import dataclasses
    from dataclasses import dataclass
    
    @dataclass
    class Def_Input:
        var1 = 3
        var2 = 4
        
    @pytest.fixture
    def def_inp():
        def_inp = Def_Input()
        return def_inp
    
    def test_1(def_inp):
    
        # make a deep copy of "def_inp"
        temp = dataclasses.replace(def_inp)
    
        temp.var1 = 5
        assert def_inp.var1 == 3
        assert temp.var1 + temp.var2 == 9