pytest configuration problem (transition from nosetests (71 sec) to pytest (1536 sec))

不羁岁月 提交于 2019-12-08 05:09:41

问题


The problem:

pytest (decided by policy) takes 1536 seconds to run the same test suite (585 tests) as nosetest, which runs in 71 seconds.

The pytest.ini files is:

[pytest]
python_files = tests_*.py *_tests.py
norecursedirs = .idea  (pycharm env).
testpaths = tests

And the file is placed at the root of the project:

root
 |-+ mod1
 | |-- core.py
 | |-- utils.py
 |-+ mod2
 | |-- core.py
 | |-- utils2.py
 |-+ tests
 | |-- test_mod1
 | |-- test_mod2
 |-+ utils (don't test).
 | |-- u1.py
 | |-- u2.py
 |- pytest.ini
 |- readme.md

Things I've checked (following advice from the 14 other SO posts):

  • The number of Pass/Fails is the same.
  • When running the tests individually with pytests they take ~ 20ms.
  • When running the folder with pytests 10-20 tests take 14-15 seconds.
  • The test suite has one environment, there's no env or os magic. Just lots of technical logic.
  • Each test_xyz.py file has it's own isolated def setup and def teardown that creates/drop an sqlite database. The tests interact with the database, by adding new transactions and checking the additions. Example:
global db

def setup():
   db = get_new_db()

def teardown():
   pass

def test_01():
   w = Widget(db)  # create widget instance.
   w.add_friend('a@b.com')
   assert 'a@b.com' in w.friends()

Questions:

  1. Do I really have to plaster @pytest.fixtures(scope='module') on the setup and teardown of every 585 tests? I hope not.

  2. What can I do to get the runtime of pytest to be similar to nosetests?


回答1:


I'm not sure why pytest chose to invoke the module setup function in a pytest_runtest_setup hook that runs once per each test instead of a module-scoped autouse fixture, but here it is:

@hookimpl(trylast=True)
def pytest_runtest_setup(item):
    if is_potential_nosetest(item):
        if not call_optional(item.obj, "setup"):
            # call module level setup if there is no object level one
            call_optional(item.parent.obj, "setup")
        # XXX this implies we only call teardown when setup worked
        item.session._setupstate.addfinalizer((lambda: teardown_nose(item)), item)

This means you'll need to rename the setup/teardown functions to setup_module()/teardown_module(). If you're on Linux/MacOS, you can use sed combined with grep for batch renaming:

$ grep -lr "\(def setup():\|def teardown():\)" | \
  xargs sed -i 's/def setup():/def setup_module():/g;s/def teardown():/def teardown_module():/g'


来源:https://stackoverflow.com/questions/55904597/pytest-configuration-problem-transition-from-nosetests-71-sec-to-pytest-1536

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!