Reputation: 21
How to pass command line option as variable to my pytest non test file e.g. database name.
When i try:
import sys
import getopt
"""argv = sys.argv[1:]
opts, args = getopt.getopt(argv, "e:")
for opt, arg in opts:
if opt in ['-e']:
if arg == "test1":
base_url = "url-test1.com"
db_name = "db_test1"
elif arg == 'test2':
base_url = "url-test2.com"
db_name = "db_test2"
elif arg == 'test3':
base_url = "url-test3.com"
db_name = "db_test3"
return base_url
and run
python -m pytest -e test1
looks like pytest can't get -e flag
ERROR: usage: main.py [options] [file_or_dir] [file_or_dir] [...]
main.py: error: unrecognized arguments: -e
inifile: None
I also try pytest addoption and passing variable to test files works fine but how to pass cmnd line option as value to non test file?
def pytest_addoption(parser):
parser.addoption("--url", action="store", default="url-test1.com")
parser.addoption("--db", action="store", default="test1")
@pytest.fixture()
def url(request):
return request.config.getoption("--url")
def db_name(request):
return request.config.getoption("--db") #I want to pass this value to mysql.connector as database=db_name
EDIT 1
so my db_connect.py lokks like that
import mysql.connector
import argparse
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--db', required=True, type=str, help="Your database name")
return parser.parse_args()
def main():
args = parse_args()
db = args.db
return db
mydb = mysql.connector.connect(
user='username',
password='password',
host='host',
database=main()
)
if __name__ == '__main__':
main()
and when i try to run
py.test --db test1
I got this error
ERROR: usage: py.test [options] [file_or_dir] [file_or_dir] [...]
py.test: error: unrecognized arguments: --db
inifile: None
but when i run
py.test
i got
usage: py.test [-h] --db DB
py.test: error: the following arguments are required: --db
argument is required but when i pass it is unrecognized. How to handle it?
Upvotes: 2
Views: 1912
Reputation: 1417
Welcome!
Specifically to "override" variables, modules and objects you should mock them. Mocking in testing refers to creating a fake object with similar behavior to the original one when creating the real object is expensive. Such as database connections. But, naturally, it isn't restricted to just databases. You can mock any object, as well as sys.argv
.
You can read more extensively about mocking in the pytest
docs but here's a short example
import module_to_test
def mytest(monkeypatch):
"""
Mocks the configuration parameters values.
"""
monkeypatch.setattr(module_to_test.sys, 'argv', ['somescript.py', '--db'])
That being said, I strongly recommend you do not use getopt
. That is a deprecated method to parse arguments from the world of bash
. There is a strong package called argparse
that entirely replaces any such argument boilerplate code.
import argpase
def parse_args():
"""
Parse arguments given in the command line. Expects just "--db"
"""
parser = argparse.ArgumentParser()
parser.add_argument('--db', required=True, type=str, help="Your DB name")
return parser.parse_args()
def main():
args = parse_args()
db = args.db
print(f"Wrap 10 to {db}. Engage!")
if __name__ == '__main__':
main()
Great work on that argparse
!
Now, you can simply mock it. You don't need it parsing the command line, anymore. You want to control what it returns. So, this time, when you use monkeypatch
to mock argparse.ArgumentParser
, you'll pass in your own "dummy class" that does nothing but return fixed arguments when parser.parse_args()
is called. Here's an example of such a class (you'll probably want to tweak it)
from collections import namedtuple
class DummyParser:
def add_argument(self, *_, **__):
"""
We know what arguments we want, we don't need to implement this.
"""
pass
def parse_args():
"""
Money time!
"""
fake_return_class = namedtuple('Namespace',
['db', 'the value we want for db'])
args = fake_return_class(db="the value we want")
return args
fake_parser = DummyParser()
fake_args = fake_parser.parse_args()
print(fake_args.db)
One tweak could be to make it a little more reusable and add your own constructor of what'll db
be equal to.
Upvotes: 1