pytest-dev / pytest-timeout

MIT License
216 stars 64 forks source link

Not use pytest.fixture after timeout #23

Closed pytest-timeout-bot closed 6 years ago

pytest-timeout-bot commented 6 years ago

Original report by Anonymous.


After a global timeout each test initializes pytest.fixture and then fails. Why they can't fail immediately?

pytest-timeout-bot commented 6 years ago

Original comment by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


Could you provide a small example which demonstrates the problem you're seeing please?

Thanks!

pytest-timeout-bot commented 6 years ago

Original comment by Anonymous.


File test_timeout.py

#!python

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import pytest
import datetime
import time

DIR_TEST = os.path.dirname(os.path.abspath(__file__))

@pytest.fixture()
def create_file():
    open(DIR_TEST + "/" + datetime.datetime.today().strftime("%c %f"), "w").close()

def test_001(create_file):
    time.sleep(10)

def test_002(create_file):
    time.sleep(10)

def test_003(create_file):
    time.sleep(10)

command line

#!bash

py.test --timeout=3
pytest-timeout-bot commented 6 years ago

Original comment by Anonymous.


If the fixture has a high cost (for example, a selenium browser), then we will get a hang on the host.

pytest-timeout-bot commented 6 years ago

Original comment by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


Sorry, still not sure what you mean. When running your example I get this:

> py.test --timeout=3 test.py                                               5ms
============================= test session starts =============================
platform linux2 -- Python 2.7.14, pytest-3.3.1, py-1.5.2, pluggy-0.6.0
rootdir: /tmp/sandbox, inifile:
plugins: timeout-1.2.1
timeout: 3.0s method: signal
collected 3 items                                                             

test.py FFF                                                             [100%]

================================== FAILURES ===================================
__________________________________ test_001 ___________________________________

create_file = None

    def test_001(create_file):
>       time.sleep(10)
E       Failed: Timeout >3.0s

test.py:17: Failed
__________________________________ test_002 ___________________________________

create_file = None

    def test_002(create_file):
>       time.sleep(10)
E       Failed: Timeout >3.0s

test.py:20: Failed
__________________________________ test_003 ___________________________________

create_file = None

    def test_003(create_file):
>       time.sleep(10)
E       Failed: Timeout >3.0s

test.py:23: Failed
========================== 3 failed in 9.08 seconds ===========================

This seems to behave correctly to me, each test times out after 3s.

pytest-timeout-bot commented 6 years ago

Original comment by Anonymous.


But each test creates a file. But this is not good and it is not necessary. Because the test should already fall on timeout, and allocation of resources fixture can be expensive. I expect that test_001 will create the file, and the rest will fall without initializing the fixture.

pytest-timeout-bot commented 6 years ago

Original comment by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


Your fixture is function-scoped so will be created every time. If you want caching of your fixture between tests then you should use a higher scope, see https://docs.pytest.org/en/latest/fixture.html#scope-sharing-a-fixture-instance-across-tests-in-a-class-module-or-session for more details on the scope.

So I think your example should be:

import time

import pytest

@pytest.fixture(scope='session')
def fix():
    time.sleep(10)

def test_foo(fix):
    assert 1

def test_bar(fix):
    assert 1

Executing this with pytest --timeout=3 works as expected, the timeout occurs in the first test, in the second the exception raised in the fixture is cached by pytest and re-used without delay.

pytest-timeout-bot commented 6 years ago

Original comment by Anonymous.


Sry I made mistake. I have another problem

Variable from fixture scope not delete.

New example:

File test_del.py:

#!python

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import pytest
import datetime
import time

DIR_TEST = os.path.dirname(os.path.abspath(__file__))

class TempFile(object):

    def __init__(self, path):
        self.path = DIR_TEST + "/" + datetime.datetime.today().strftime("%c %f")
        open(self.path, "w").close()

    def __del__(self):
        if os.path.exists(self.path):
            os.remove(self.path)

@pytest.fixture()
def temp_file():
    t = TempFile(DIR_TEST)
    time.sleep(20)    

def test_001(temp_file):
    assert 1 == 1

def test_002(temp_file):
    assert 1 == 1

If I call py.test all temp files in test dir delete. But if I call py.test --timeout 5 all temp file save. Is it a bug? Or I do mistake again :D ?

pytest-timeout-bot commented 6 years ago

Original comment by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


Your del won't get called since the traceback on test failure, which is kept by pytest, keeps a reference to your object. You should read up on pytest finalizers in the pytest documentation (and probably also on the tmpdir built-in fixture.

pytest-timeout-bot commented 6 years ago

Original comment by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


Please use pytest-dev@python.org for general questions about pytest or it's plugins. The issue tracker is for reporting bugs.