pytest-concurrent icon indicating copy to clipboard operation
pytest-concurrent copied to clipboard

cannot work with fixture

Open bglmmz opened this issue 5 years ago • 5 comments

python 3.7.4 pytest 5.2.0 pytest-concurrent 0.2.2 gevent 1.4.0

Here is my test case, the expected result is: module_env_fixture runs once, global_env_fixture runs once, and all cases passed.

Run the command "pytest test_loop.py -s", the result is expected.

But run the command "pytest test_loop.py --concmode=mthread -s", or "pytest test_loop.py --concmode=asyncnet -s", the result is not expected, module_env_fixture runs several times,global_env_fixture runs several times, and get some error messages.

Is it caused by "time.sleep(1)" in env.py?

conftest.py

import pytest

from env import create_env


@pytest.fixture(scope="session", autouse=True)
def global_env_fixture(request):
    print("begin of global_env_fixture>>>>>>>>>>>>>>>>>>>")

    env = create_env()

    yield env
    print("end of  global_env_fixture>>>>>>>>>>>>>>>>>>>")

env.py

import time


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

    def getName(self):
        return self.name

class TestEnvironment:
    def __init__(self, node):
        self.node = node
        # do something
        time.sleep(1)

def create_env() -> TestEnvironment:
    node = Node("test_node")

    return TestEnvironment(node)

test_loop.py

import random
import time

import pytest

from env import Node, TestEnvironment


@pytest.fixture(scope="module", autouse=False)
def module_env_fixture(global_env_fixture) -> (Node, TestEnvironment):

    print("begin of module fixture]]]]]]]]]]]]]]]]]]]]")

    global_env = global_env_fixture
    node = global_env.node
    yield node, global_env

    print("end of module fixture]]]]]]]]]]]]]]]]]]]]")


def test_case_1(module_env_fixture):
    node, module_env = module_env_fixture
    print("begin: test_case_1 ::{}".format(node.getName()))
    callAPI("test_case_1")
    print("end: test_case_1")
    pass

def test_case_2(module_env_fixture):
    node, module_env = module_env_fixture
    print("begin: test_case_2 ::{}".format(node.getName()))
    callAPI("test_case_2")
    print("end: test_case_2")
    pass

def test_case_3(module_env_fixture):
    node, module_env = module_env_fixture
    print("begin: test_case_3 ::{}".format(node.getName()))
    callAPI("test_case_3")
    print("end: test_case_3")
    pass

def callAPI(name):
    print("call any API: {}".format(name))
    getResult(name)


def getResult(name):
    for x in range(2):
        rand = random.randint(1, 3)
        time.sleep(rand)
        print("try to get result for: {}, sleep: {}".format(name, rand))

bglmmz avatar Oct 21 '19 08:10 bglmmz

if I update the env.py like this, The result is still not expected.

from concurrent.futures import wait, ALL_COMPLETED
from concurrent.futures.thread import ThreadPoolExecutor


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

    def getName(self):
        return self.name

def initNode():
    sum = 0
    for i in range(1000000):
        sum = sum + i

class TestEnvironment:
    def __init__(self, node):
        self.node = node
        futures = []
        with ThreadPoolExecutor(max_workers=2) as executor:
            future = executor.submit(initNode)
            futures.append(future)
            wait(futures, timeout=10, return_when=ALL_COMPLETED)

def create_env() -> TestEnvironment:
    node = Node("test_node")

    return TestEnvironment(node)

bglmmz avatar Oct 21 '19 09:10 bglmmz

and if I update the env.py like this ( make simple), the command "pytest test_loop.py --concmode=mthread -s" seems to work fine, but the command "pytest test_loop.py --concmode=asyncnet -s" still seems not to work fine.

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

    def getName(self):
        return self.name

class TestEnvironment:
    def __init__(self, node):
        self.node = node


def create_env() -> TestEnvironment:
    node = Node("test_node")

    return TestEnvironment(node) 

bglmmz avatar Oct 21 '19 09:10 bglmmz

i'm getting similar issue that you have, seems it's caused by autouse param in fixture

in my case i'm running my test like python -m pytest -s -v test_async_service.py::test_pytest_concurrent --concmode=mthread

simple test.py:


iterations = [x for x in range(5)]

@pytest.mark.parametrize('iteration', iterations, ids=iterations)
def test_pytest_concurrent(iteration):
    pass

and conftest.py

@pytest.fixture(scope='session', autouse=True)
def fix():
    print('---------->')
    print('----------> session scope fixture executed')
    print('----------> \n')

Executing several times, once all is ok, session fixture executes only once and all tests are passed, the second time session fixture executes several times and i'm getting error below:

Traceback (most recent call last):
  File "C:\Users\vlad\AppData\Local\Programs\Python\Python38\Lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\vlad\AppData\Local\Programs\Python\Python38\Lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pytest\__main__.py", line 7, in <module>
    raise SystemExit(pytest.main())
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\_pytest\config\__init__.py", line 124, in main
    ret = config.hook.pytest_cmdline_main(
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\hooks.py", line 286, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\manager.py", line 93, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\manager.py", line 84, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\callers.py", line 208, in _multicall
    return outcome.get_result()
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\_pytest\main.py", line 240, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\_pytest\main.py", line 228, in wrap_session
    config.hook.pytest_sessionfinish(
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\hooks.py", line 286, in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\manager.py", line 93, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\manager.py", line 84, in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\callers.py", line 203, in _multicall
    gen.send(outcome)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\_pytest\terminal.py", line 717, in pytest_sessionfinish
    outcome.get_result()
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\callers.py", line 80, in get_result
    raise ex[1].with_traceback(ex[2])
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\pluggy\callers.py", line 187, in _multicall
    res = hook_impl.function(*args)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\_pytest\runner.py", line 80, in pytest_sessionfinish
    session._setupstate.teardown_all()
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\_pytest\runner.py", line 337, in teardown_all
    self._teardown_with_finalization(key)
  File "C:\Users\vlad\PycharmProjects\async-service\venv\lib\site-packages\_pytest\runner.py", line 331, in _teardown_with_finalization
    assert colitem in self.stack
AssertionError

vmred avatar Jun 08 '20 19:06 vmred

any ideas why this happens and how to fix?

vmred avatar Jun 08 '20 19:06 vmred

Probably could be usefull:

avoided my stacktrace via using pytest_sessionstart hook instead of session level fixture with autouse param:

my conftest.py:

def pytest_sessionstart(session):
    print('---------->')
    print('----------> session started')
    print('---------->')

vmred avatar Jun 08 '20 19:06 vmred