1
votes

I used to use a runner.py with my pytest framework in order to get around the bug with combining markers and string params, e.g.:

-k 'foo' -m 'bar'

I also used the runner to get the test run's starting timestamp and create an output folder output// to which I write my logs and the html report, save any screenshots, etc.

runner.py excerpt:

    timestamp = time.strftime('%y%m%d-%H%M%S')
    # the following are used by conftest.py
    output_path = utils.generate_output_path(timestamp) 
    folder = utils.create_output_folder(output_path)

    def main():
        args = sys.argv[1:]
        args.append('-v')
        args.append('--timestamp=%s' % timestamp)
        args.append('--output_target=%s' % folder)
        args.append('--html=%s/results.html' % folder)
        pytest.main(args, plugins=plgns)

    if __name__ == "__main__":
        main()

I want to lose the runner.py and use straight CLI args and fixtures/hooks but not manually pass in timestamp, output_target, or the html report path, but have so far been unable find a way to change that config, for example by modifying config.args.

How can I dynamically write timestamp, output_target, and the html path so that pytest uses them during initialization?

1

1 Answers

0
votes

Here's what I did:

in my pytest.ini I added a default command line option for the html report, so that there is a configuration attribute that I can modify:

addopts = --html=output/report.html

in my conftest.py, I added this pytest_configure() call

def pytest_configure(config):
"""
    Set up the output folder, logfile, and html report file; 
    this has to be done right after the command line options 
    are parsed, because we need to rewrite the pytest-html path.

    :param config: pytest Config object
    :return: None
"""
# set the timestamp for the start of this test run
timestamp = time.strftime('%y%m%d-%H%M%S')

# create the output folder for this test run
output_path = utils.generate_output_path(timestamp)
folder = utils.create_output_folder(output_path)

# start logging
filename = '%s/log.txt' % output_path
logging.basicConfig(filename=filename,
                    level=logging.INFO,
                    format='%(asctime)s %(name)s.py::%(funcName)s() [%(levelname)s] %(message)s')

initial_report_path = Path(config.option.htmlpath)
report_path_parts = list(initial_report_path.parts)

logger.info('Output folder created at "%s".' % folder)
logger.info('Logger started and writing to "%s".' % filename)

# insert the timestamp
output_index = report_path_parts.index('output')
report_path_parts.insert(output_index + 1, timestamp)

# deal with doubled slashes
new_report_path = Path('/'.join(report_path_parts).replace('//', '/'))

# update the pytest-html path
config.option.htmlpath = new_report_path
logger.info('HTML test report will be created at "%s".' % config.option.htmlpath)

This is logged as: 2018-03-03 14:07:39,632 welkin.tests.conftest.py::pytest_configure() [INFO] HTML test report will be created at "output/180303-140739/report.html".

The html report is written to the appropriate output/<timestamp>/ folder. That's the desired result.