27

I have a session scoped fixture in conftest.py

@pytest.fixture(scope="session",autouse=True)
def log(request):
    testlog = LogUtil(testconf.LOG_NAME).get()
    return testlog

This is loaded and works as expected when a test method is defined in mytest.py as follows:

def test_hello_world(self, log):
        log.info("hello world test")

Is there a way to use the fixture (since its autouse enabled) without having to add the extra "log" parameter to test methods?

def test_hello_world(self):
        log.info("hello world test") #log is not found

@pytest.mark.usefixtures("log")
def test_hello_world2(self):
        log.info("hello world test") #log is not found

def test_hello_world3(self,log):
        log.info("hello world test") #log object is accessible here

Error - NameError: name 'log' is not defined

Feuermurmel
  • 9,490
  • 10
  • 60
  • 90
tjmn
  • 469
  • 1
  • 6
  • 11

2 Answers2

20

You typically use autouse fixtures when you want to use them for setup/teardown only.

If you need access to the object the fixture returns, you'll need to specify it as an argument like in your first example.

The Compiler
  • 11,126
  • 4
  • 40
  • 54
  • 2
    Thanks for the response. It becomes cumbersome to add arguments to each test when the no of tests start growing. Right now the options seem to be: 1) Create a global variable and update it using the fixture defined in conftest.py 2) Create a base class with a static variable(No fixture needed) – tjmn May 18 '16 at 10:10
  • 8
    **I completely concur with [tj23](https://stackoverflow.com/users/1257065/tj23).** The inability to actually access fixtures implicitly declared via either `autouse` or `usefixtures` makes such fixtures useless for most purposes – in my case, _all_ purposes. The usual alternative is to **(A)** define a single abstract fixture requiring multiple real fixtures and then **(B)** have tests require the former rather than the latter. In my case, however, fixture scoping constraints prohibit this. _Urgh!_ – Cecil Curry May 25 '16 at 02:03
  • 2
    I disagree - personally I also often use fixtures to simply have some setup/teardown (e.g. patching) and don't actually need access to it. Could you elaborate why you'd need *multiple* real fixtures and an abstract fixture? What's your use-case? Maybe we should take this to the [pytest tracker](https://github.com/pytest-dev/pytest/issues) though. – The Compiler May 25 '16 at 13:00
  • 1
    @TheCompiler - Here is my use case, I plan to have a common instance of logger, http client and ssh client across all tests. So, I have added fixtures to initialize these in conftest.py and referred them in tests. It would be nice to just add the use fixture marker and start using it within the tests rather than having to add it as an argument to each test method. – tjmn Jun 02 '16 at 09:48
  • 3
    The only way how I can possibly imagine this to work is by pytest injecting globals into the module and changing them between every test... which sounds painful and is probably going to break with parallelized testing (`pytest-xdist`) and quite possibly some other scenarios. – The Compiler Jun 02 '16 at 12:57
8

Your log function is not a fixture. Treat it the same as any other library routine. Eg: add it to a common module and import as desired.

common.py

import logging
import os

logger = logging.getLogger()
project_id = os.getenv('PROJECT_ID', 'maris-baccus')

test_stuff.py

from common import logger, project_id

def test_this():
    logger.info(f'This is the {project_id}')
John Mee
  • 50,179
  • 34
  • 152
  • 186