[Python] Pytest Running multiple test in one session but the Environment Configuration does...

Discussão em 'Python' iniciado por Stack, Abril 17, 2025.

  1. Stack

    Stack Membro Participativo

    I have created a framework which comprises of Test_Runner.xlsx file, excel_to_python.py file which reads data from excel and site_credentials.py file which actually holds the value of the environment configurations.

    Problem which I am facing right now is that., Let us say, if I have three test cases planned as follows.

    • Test_01 to be run on Environment 03.
    • Test_02 to be run on Environment 01.
    • Test_03 to be run on Environment 04.

    So, the above mentioned configuration and test case details are maintained in Test_Runner.xlsx file. My excel_to_python.py reads it and then respective pytest cases are run and simultaneously the site_credentials.py is also updated with the configuration details.

    Now the actual problem is that, when I run these tests individually using subprocess, then all works fine and a single pytest HTML report is generated for each planned cases separately.

    What I am expecting is that, test cases should execute in one pytest session itself and the configuration details should update as expected for the respective test case.

    But right now, the problem is that the test cases are executed as planned but the environment details are not updated properly as expected.

    As mentioned above, the site_credentials.py holds up the last case value only. like for the below scenario.

    • Test_01 to be run on Environment 03.
    • Test_02 to be run on Environment 01.
    • Test_03 to be run on Environment 04.

    all the tests will run on Environment 04 only. But I want it to run as planned for each respective cases.

    How do I ensure that my site_credentials.py gets updated as what I am hoping for. Tried pytest hookups and updating conftest.py and then making site_credentials.py have the global variables. But nothing seems to work out.

    • I am new to pytest, and any help or the insight related to my framework design will be appreciated. NOTE: Same issue I am facing in updating the access_certificate_name variable too.

    Test_Runner.xlsx The below file actually has Execution State column, if the status == Y then that case will be executed and if it is N then it won't and will be skipped. It has multiple sheets. But this is the one which I am interested on and where I am actually facing issue with updating of environment details.

    My Excel file

    excel_to_python.py Code.,

    import datetime
    import json
    import shutil
    import pandas as pd
    import subprocess
    import numpy as np
    import os
    import re


    class ExcelToPython:
    def __init__(self, automation_project_directory, excel_file_name):
    self.project_directory = automation_project_directory
    self.file_path = os.path.join(automation_project_directory, excel_file_name)
    self.df_config = self.read_excel('Config')
    self.df_environments = self.read_excel('Environments')
    self.df_credentials = self.read_excel('Credentials')

    def read_excel(self, sheet_name):
    df = pd.read_excel(self.file_path, sheet_name=sheet_name, engine='openpyxl')
    return df.replace(np.nan, '', regex=True)

    def update_site_credentials(self, key, value):
    with open('site_credentials.py', 'r', encoding='utf-8', errors='ignore') as file:
    lines = file.readlines()
    with open('site_credentials.py', 'w', encoding='utf-8', errors='ignore') as file:
    for line in lines:
    if line.strip().startswith(key):
    file.write(f"{key} = {value}\n")
    else:
    file.write(line)

    def validate_data(self):
    validation_messages = []
    validators = {
    'EXECUTION STATE (Y/N)': lambda x: isinstance(x, str) and x.strip().upper() in ['Y', 'N'],
    'TEST CASE ID': lambda x: bool(re.match(r'^[\w\s-]+$', x)),
    'TEST DESCRIPTION': lambda x: bool(re.match(r'^[\w\s-]+$', x)),
    'ENVIRONMENT NUMBER': lambda x: str(x).isdigit(),
    'CERTIFICATE NAME': lambda x: x.strip().endswith('.pfx')
    }
    for index, row in self.df_config.iterrows():
    for column, validator in validators.items():
    if not validator(row[column]):
    validation_messages.append(f"Row {index + 1}: Invalid {column} - {row[column]}")
    return validation_messages

    def find_test_file(self, root, test_case_title):
    for dirpath, _, filenames in os.walk(root):
    for filename in filenames:
    if filename == f'{test_case_title}.py':
    return os.path.join(dirpath, filename)
    return None

    def update_environments(self):
    """
    This function prepares Environment Dictionary using the available Environment Details in Excel Sheet.
    :return: None
    """
    try:
    environments_data = {
    int(row['Environment Number']): {
    "url": row['URL'],
    "password": str(row['Password']),
    "mws_url": row['MWS URL'],
    "db_username": row['DB Username'],
    "db_password": str(row['DB Password']),
    "db_hostname": row['DB Hostname'],
    "db_port": str(row['DB Port']),
    "db_servicename": row['DB Servicename']
    }
    for _, row in self.df_environments.iterrows()
    }
    self.update_site_credentials('environments', environments_data)
    except Exception as e:
    print(f"Error occurred while reading and updating environment details from excel: {e}")

    def update_credentials(self):
    """
    This function will update the credentials data from Excel sheet and write it in python file.
    :return: None
    """
    try:
    credentials_data = {
    key: self.df_credentials.loc[self.df_credentials['Particulars'] == key, 'Values'].values[0]
    for key in ['Party', 'Participant', 'User', 'Jurisdiction', 'Region']
    }
    for key, value in credentials_data.items():
    self.update_site_credentials(key.lower().replace(' ', '_'), f"'{value}'")
    except Exception as e:
    print(f"Error occurred while reading and updating credentials details from excel: {e}")

    def run_tests(self):
    validation_messages = self.validate_data()
    if self.df_config.empty or self.df_config.iloc[1:].isnull().any().any() or self.df_config.isin(
    ['']).any().any():
    print("No data to process or there are blank rows/cells in the table data.")
    elif validation_messages:
    print(
    "Excel sheet Data Validation failed due to below reasons. Please check/update the data and try again!")
    for message in validation_messages:
    print(message)
    else:
    test_cases_root = '../test_cases'
    report_folder = '../reports'
    os.makedirs(report_folder, exist_ok=True)

    for _, row in self.df_config.iterrows():
    test_description = row['TEST DESCRIPTION']
    test_file_path = self.find_test_file(test_cases_root, test_description.replace(' ', '_').lower())

    if row['EXECUTION STATE (Y/N)'].strip().upper() == 'Y':
    if test_file_path:
    # Update the environment and cert just before running this test
    self.update_site_credentials('environment_to_test', int(row['ENVIRONMENT NUMBER']))
    self.update_site_credentials('access_certificate_name', f"r'{row['CERTIFICATE NAME'].strip()}'")

    time_stamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
    report_file = f'Test_Report_{test_description.replace(" ", "_")}_{time_stamp}.html'

    pytest_command = [
    'pytest',
    test_file_path,
    f'--html={os.path.join(report_folder, report_file)}',
    '--self-contained-html',
    # '--tb=short',
    '-W', 'ignore::DeprecationWarning'
    ]
    print(f"Running test for: {test_description}")
    subprocess.run(pytest_command)
    else:
    print(f"Test file for {test_description} not found. Skipping.")
    else:
    print(f"Skipping test case: {test_description}")


    site_credentials.py

    # To update the variables based on the environment number
    environment_to_test = 4
    access_certificate_name = r'test3@testing.pfx'


    # Environment Details Dictionary (auto populates) can be ignored
    environments = {}

    def get_environment_details():
    if environment_to_test not in environments:
    raise ValueError(f"Invalid Environment: {environment_to_test}")
    return environments[environment_to_test]


    # SSL/TLS Certificates details (auto populates) can be ignored
    cert_dict = {}


    def get_certificate_password():
    if access_certificate_name in cert_dict:
    return cert_dict[access_certificate_name]
    raise ValueError(f"Invalid certificate name: {access_certificate_name}")


    def get_certificate_path():
    if access_certificate_name is None:
    raise ValueError("Certifacte name not set; credentials not initialized yet")
    return fr'..\certs\{access_certificate_name}'

    Continue reading...

Compartilhe esta Página