简体   繁体   中英

How to pass an environment variable in command line to pytest to test a function

I have a script using os.environ.get() to get variable from command line something like JENKINS_HOST="xx" JENKINS_AUTH="xx" JENKINS_TOKEN="xx" python script.py

In script.py has a function it likes this:

def init_auth():
    login_mode = True
    JENKINS_HOST = os.environ.get("JENKINS_HOST")
    JENKINS_AUTH = os.environ.get("JENKINS_AUTH")
    JENKINS_TOKEN = os.environ.get("JENKINS_TOKEN")

when I use pytest to test the function init_auth(), how could I transfer the cli environment to this function?

I'm not sure I quite understood your question.. basically, instead of retrieving values from the environment, you want to retrieve them from the CLI?

If so, one way I did that was by creating a conftest.py file in the same directory as the test and use the pytest_addoption and pytest_generate_tests hooks.

conftest.py :

def pytest_addoption(parser):
    """
    Add CLI options to `pytest` to pass those options to the test cases.
    These options are used in `pytest_generate_tests`.
    """
    parser.addoption('--jenkins-host')
    parser.addoption('--jenkins-auth')
    parser.addoption('--jenkins-token')

def pytest_generate_tests(metafunc):
    metafunc.parametrize(
        'jenkins_host, jenkins_auth, jenkins_token',
        [(metafunc.config.getoption('jenkins_host'),
          metafunc.config.getoption('jenkins_auth'),
          metafunc.config.getoption(jenkins_token'))]

TestFile.py

class TestThis:
    def test_my_thing(jenkins_host, jenkins_auth, jenkins_token):
        # Do tests here

CLI

pytest TestFile.py --jenkins-host "http://my-jenkinshost.com" --jenkins-auth whatever --jenkins-token THE_TOKEN

The arguments in the test case are parametrized (the equivalent of adding the annotation @pytest.mark.parametrize(...) in pytest_generate_tests .

This works well and it's fully supported by pytest . It's a basic example as there's a lot more you can do. See here more info on how these and other hooks work.

Lets assume you want to test a function like this:

def foo():
    something = os.environ.get("SOMETHING")
    if something=="BAD":
       raise Exception("BAM")

It is used in a little application like this:

def main():
   try:
      foo()
      print("OK")
   except:
      print("SAD")

I can specify environment values on the command line that eventually get to foo

$ SOMETHING=BAD ./my_app
SAD
$ SOMETHING=ELSE ./my_app
OK

Now, I want to test the behaviour of foo, but I need to be careful not to change my environment settings, so I need to set and restore them, even should the test go bad. That looks something like:

def test_foo_ok():
  orig = os.environ.get("SOMETHING")
  os.environ["SOMETHING"]="ELSE"
  try:
     foo()
  finally:
     if orig is None:
        del os.environ["SOMETHING"]
     else:
        os.environ["SOMETHING"]=orig

def test_foo_bad():
  orig = os.environ.get("SOMETHING")
  os.environ["SOMETHING"]="BAD"
  try:
    with pytest.raises(Exception) as excinfo:   
        foo()   
    assert str(excinfo.value) == "BAM" 
  finally:
     if orig is None:
        del os.environ["SOMETHING"]
     else:
        os.environ["SOMETHING"]=orig

You could wrap the boilerplate in those into a decorator if you wanted. I'd call it something like @testwithenv then the tests would look cleaner.

@testwithenv({"SOMETHING","ELSE"})
def test_foo_ok():
  foo()

@testwithenv({"SOMETHING","BAD"})
def test_foo_bad():
  with pytest.raises(Exception) as excinfo:   
    foo()   
  assert str(excinfo.value) == "BAM" 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM