4

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?

1
  • You can pass arguments in command line like python script.py <jenkins_host> <jenkins_auth> and retrieve them as sys.argv[1] , sys.argv[2] etc.. Commented Feb 27, 2019 at 8:16

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

3 Comments

I think the missing part of this is that the init_auth is getting called inside the tests, and the code can't be changed to pass these variables in. This means the test_my_thing function will probably start with a bunch of os.environ.set('JENKINS_HOST', jenkins_host) etc. And probably some additional code to get the initial values and restore them when the test completes (with pass or fail). You need to restore them as otherwise they may pollute other tests.
config.getoption(..) has a default parameter, so the lines can be changed to metafunc.config.getoption('jenkins_host', default= os.environ.get('JENKINS_HOST')) which then uses the environment var if not defined in the CLI. docs.pytest.org/en/latest/…
Thanks, both of you, this is what I want. I hope I can get variables from CLI like this pytest xxx.py --jenkins-host "my-jenkinshost.com" --jenkins-auth="xxxx". I didn' t know that there are hooks in pytest, I am a beginner for pytest.
1

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" 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.