0

The Python "teardown_class" is not behaving as I expect it to. Below is a summary of my code:

@classmethod
def setup_class(cls):
    cls.create_table(table1)
    cls.create_table(table2)
    cls.create_table(table3)

@classmethod
def create_table(cls, some_arg_here):
    """Some code here that creates the table"""

def test_foo(self):
    """Some test code here"""

@classmethod
def teardown_class(cls):
    """Perform teardown things"""

I believe the way it is executing is that:

  1. create_table is being called from setup with 1st parameter (table1)
  2. Code in create_table executes
  3. Code in teardown_class executes
  4. 1-3 above is executed again with the 2nd parameter
  5. 1-3 above is executed again with the 3rd parameter
  6. Code in test_foo executes

How I expect it to perform:

  1. create_table is called with 1st parameter (table1)
  2. Code in create_table executes
  3. create_table is called with 2nd parameter (table 2)
  4. Code in create_table executes
  5. create_table is called with 3rd parameter (table 3)
  6. Code in create_table executes
  7. Code in test_foo executes
  8. Code in teardown_class executes

Python 2.7.10, pytest-3.6.2, py-1.5.3, pluggy-0.6.0

user1599401
  • 65
  • 1
  • 2
  • 10

2 Answers2

1

Your classmethod misses the cls param:

@classmethod
def create_table(some_arg_here):
    """Some code here that creates the table"""

Change it to

@classmethod
    def create_table(cls, some_arg_here):

I modified your code and added some prints:

class TestClass:

    @classmethod
    def setup_class(cls):
        print("Setting up")
        cls.create_table('table1')
        cls.create_table('table2')
        cls.create_table('table3')

    @classmethod
    def create_table(cls, some_arg_here):
        print("Creating:", some_arg_here)
        """Some code here that creates the table"""

    def test_foo(self):
        print('Running test_foo')
        """Some test code here"""

    @classmethod
    def teardown_class(cls):
        print("Tearing down")
        """Perform teardown things"""

If you run it with -s you will get the following result:

test.py Setting up
Creating: table1
Creating: table2
Creating: table3
Running test_foo
.Tearing down

As you can see, everything works as expected. The setup_class is called, tables are created (all 3), test method runs and then teardown_class kicks in.

If you add a function test_bar() you will get:

test.py Setting up
Creating: table1
Creating: table2
Creating: table3
Running test_foo
.Running test_bar
.Tearing down

Seems also to be fine to me..

Do you have some more hints for your assumption something is wrong?

  • I've come to find that the issue occurs when I call another method from the setup method. If I put the code from create_table directly into the setup method, it works as expected: all the code in the setup method runs, then the test, then the teardown. But if I call create_table from setup (multiple times), then after each call, it runs teardown. Is this really how it's expected to perform? If so I need a workaround... – user1599401 Jun 28 '18 at 03:32
0

I was able to find the solution. I recreated the create_table function as an inner function, inside of the setup function.

@classmethod
def setup_class(cls):
    def create_table(some_arg_here):
       """Some code here that creates the table"""

    create_table(table1)
    create_table(table2)
    create_table(table3)

def test_foo(self):
    """Some test code here"""

@classmethod
def teardown_class(cls):
    """Perform teardown things"""

And now it runs as I expect it to, in this sequence:

  1. Run create_table once for table1 param
  2. Run create_table once for table2 param
  3. Run create_table once for table3 param
  4. Run test_foo
  5. Run teardown_class

It seems that any/every time a function that is outside of setup is called from setup, it causes the teardown function to run directly after the code in the outer function runs, and that was the issue I was facing.

user1599401
  • 65
  • 1
  • 2
  • 10