Setting dynamic folder and report name in pytest

…衆ロ難τιáo~ 提交于 2020-05-09 05:57:08

问题


I have a problem with setting report name and folder with it dynamically in Python's pytest. For example: I've run all pytest's tests @ 2020-03-06 21:50 so I'd like to have my report stored in folder 20200306 with name report_2150.html. I want it to be automated and triggered right after the tests are finished.

I'm working in VS Code and I'm aiming to share my work with colleagues with no automation experience so I'm aiming to use it as "click test to start".

My project structure:

webtools/
|── .vscode/
|──── settings.json
|── drivers/
|── pages/
|── reports/
|── tests/
|──── __init__.py
|──── config.json
|──── conftest.py
|──── test_1.py
|──── test_2.py
|── setup.py

Code samples:

settings.json

{
    "python.linting.pylintEnabled": false,
    "python.linting.flake8Enabled": true,
    "python.linting.enabled": true,
    "python.pythonPath": "C:\\Users\\user\\envs\\webtools\\Scripts\\python.exe",
    "python.testing.pytestArgs": [
        "tests",
        "--self-contained-html",
        "--html=./reports/tmp_report.html" 
    ],
    "python.testing.unittestEnabled": false,
    "python.testing.nosetestsEnabled": false,
    "python.testing.pytestEnabled": true,
    "python.testing.unittestArgs": [
        "-v",
        "-s",
        "./tests",
        "-p",
        "test_*.py"
    ]
}

config.json

{
    "browser": "chrome",
    "wait_time": 10
}

conftest.py

import json
import pytest
from datetime import datetime
import time
import shutil
import os


from selenium import webdriver
from selenium.webdriver import Chrome

CONFIG_PATH = 'tests/config.json'
DEFAULT_WAIT_TIME = 10
SUPPORTED_BROWSERS = ['chrome', 'explorer']


@pytest.fixture(scope='session')
def config():
    # Read the JSON config file and returns it as a parsed dict
    with open(CONFIG_PATH) as config_file:
        data = json.load(config_file)
    return data


@pytest.fixture(scope='session')
def config_browser(config):
    # Validate and return the browser choice from the config data
    if 'browser' not in config:
        raise Exception('The config file does not contain "browser"')
    elif config['browser'] not in SUPPORTED_BROWSERS:
        raise Exception(f'"{config["browser"]}" is not a supported browser')
    return config['browser']


@pytest.fixture(scope='session')
def config_wait_time(config):
    # Validate and return the wait time from the config data
    return config['wait_time'] if 'wait_time' in config else DEFAULT_WAIT_TIME


@pytest.fixture
def browser(config_browser, config_wait_time):
    # Initialize WebDriver
    if config_browser == 'chrome':
        driver = webdriver.Chrome(r"./drivers/chromedriver.exe")
    elif config_browser == 'explorer':
        driver = webdriver.Ie(r"./drivers/IEDriverServer.exe")
    else:
        raise Exception(f'"{config_browser}" is not a supported browser')

    # Wait implicitly for elements to be ready before attempting interactions
    driver.implicitly_wait(config_wait_time)

    # Maximize window for test
    driver.maximize_window()

    # Return the driver object at the end of setup
    yield driver

    # For cleanup, quit the driver
    driver.quit()


@pytest.fixture(scope='session')
def cleanup_report():
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    os.chdir("./reports")
    os.mkdir(timestamp)

    yield

    shutil.move("./tmp_report.html", "./%s/test_report.html" % timestamp)

In current situation the report is created as tmp_report.html in the reports folder, but I don't know how I can force running cleanup_report() after all tests are completed and tmp_report.html is present and complete in folder. For checking if complete I assume I'd have to verify if all html tags have their closing (or at least <html> one).

Can somebody help me with that? If you need some further code portions I'll provide them as soon as possible.

Thank you in advance!


回答1:


You can customize the plugin options in a custom impl of the pytest_configure hook. Put this example code in a conftest.py file in your project root dir:

from datetime import datetime
from pathlib import Path
import pytest


@pytest.hookimpl(tryfirst=True)
def pytest_configure(config):
    # set custom options only if none are provided from command line
    if not config.option.htmlpath:
        now = datetime.now()
        # create report target dir
        reports_dir = Path('reports', now.strftime('%Y%m%d'))
        reports_dir.mkdir(parents=True, exist_ok=True)
        # custom report file
        report = reports_dir / f"report_{now.strftime('%H%M')}.html"
        # adjust plugin options
        config.option.htmlpath = report
        config.option.self_contained_html = True

If you want to completely ignore what's passed from command line, remove the if not config.option.htmlpath: condition.

If you want to stick with your current impl, notice that on fixtures teardown, pytest-html hasn't written the report yet. Move the code from cleanup_report to a custom impl of the pytest_sessionfinish hook to ensure pytest-html has already written the default report file:

@pytest.hookimpl(trylast=True)
def pytest_sessionfinish(session, exitstatus):
    shutil.move(...)


来源:https://stackoverflow.com/questions/60571675/setting-dynamic-folder-and-report-name-in-pytest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!