Automatisation de tests API avec Python : Journalisation, Authentification et Services Fiduciaires

Gestion de la journalisation (Logging)

Dans un projet d'automatisation, les journaux sont cruciaux pour tracer l'exécution et diagnostiquer les échecs. Python propose le module logging qui peut être configuré pour structurer les sorties de manière professionnelle.

Voici une encapsulation robuste pour initialiser un gestionnaire de logs avec rotation temporelle :

import logging
import logging.handlers
import os

class LogManager:
    _instance = None

    @classmethod
    def get_logger(cls):
        if cls._instance is None:
            cls._instance = logging.getLogger("FinanceApp")
            cls._instance.setLevel(logging.INFO)
            
            # Définition du chemin du fichier
            log_dir = "logs"
            if not os.path.exists(log_dir):
                os.makedirs(log_dir)
            log_path = os.path.join(log_dir, "automation.log")

            # Rotation à minuit, conservation de 7 jours de logs
            handler = logging.handlers.TimedRotatingFileHandler(
                filename=log_path, when="midnight", interval=1, backupCount=7, encoding="utf-8"
            )
            
            # Formatage des messages
            formatter = logging.Formatter('%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s')
            handler.setFormatter(formatter)
            
            cls._instance.addHandler(handler)
        return cls._instance

# Initialisation globale pour usage dans le projet
logger = LogManager.get_logger()

Développement des interfaces d'authentification et de compte

L'automatisation des services financiers nécesssite souvent de gérer des flux complexes comme l'authentification d'identité et l'ouverture de comptes fiduciaires. L'un des défis techniques est l'envoi de données au format multipart/form-data.

class EscrowApi:
    def __init__(self, session, host):
        self.http = session
        self.host = host
        self._endpoints = {
            "verify": "/member/realname/approverealname",
            "status": "/member/member/getapprove",
            "register": "/trust/trust/register",
            "captcha": "/common/public/verifycode/{}",
            "topup": "/trust/trust/recharge"
        }

    def verify_identity(self, full_name, id_number):
        """Authentification réelle de l'utilisateur"""
        url = self.host + self._endpoints["verify"]
        payload = {"realname": full_name, "card_id": id_number}
        # L'utilisation combinée de data et files force le header multipart/form-data
        logger.info(f"Appel vérification identité : {url}")
        return self.http.post(url, data=payload, files={"dummy": ""})

    def get_escrow_status(self):
        """Vérifie l'état du compte"""
        return self.http.post(self.host + self._endpoints["status"])

    def open_escrow_account(self):
        """Initie l'ouverture du compte de confiance"""
        return self.http.post(self.host + self._endpoints["register"])

    def fetch_captcha(self, seed):
        """Récupère l'image de vérification"""
        return self.http.get(self.host + self._endpoints["captcha"].format(seed))

Extraction de données dynamiques avec BeautifulSoup

Certains services redirigent l'utilisateur vers une page tierce via un formulaire HTML injecté dans une réponse JSON. Pour automatiser cela, il faut extraire l'URL d'action et les champs input cachés.

from bs4 import BeautifulSoup

def extract_form_context(response):
    """
    Parse la réponse pour extraire les paramètres d'un formulaire HTML masqué.
    """
    raw_html = response.json().get("description", {}).get("form", "")
    if not raw_html:
        return None, {}

    soup = BeautifulSoup(raw_html, "html.parser")
    form_tag = soup.find("form")
    action_url = form_tag.get("action")
    
    form_data = {}
    for tag in soup.find_all("input"):
        name = tag.get("name")
        value = tag.get("value")
        if name:
            form_data[name] = value
            
    return action_url, form_data

Implémentation des tests unitairse paramétrés

L'utilisasion de unittest avec parameterized permet de tester plusieurs scénarios (succès, erreurs de saisie) avec une seule méthode de test.

import unittest
import requests
from parameterized import parameterized

class TestEscrowFlow(unittest.TestCase):
    def setUp(self):
        self.session = requests.Session()
        self.api = EscrowApi(self.session, "http://api.fintech.example")
        # Logique de connexion préalable obligatoire ici

    def tearDown(self):
        self.session.close()

    def test_account_opening_and_redirection(self):
        """Test complet de l'ouverture de compte et redirection tierce"""
        try:
            resp = self.api.open_escrow_account()
            self.assertIn("form", resp.text)
            logger.info("Analyse du formulaire de redirection...")

            # Simulation de l'interaction avec le tiers
            redirect_url, data = extract_form_context(resp)
            final_resp = self.session.post(redirect_url, data=data)
            self.assertIn("OK", final_resp.text)
            logger.info("Redirection tierce validée avec succès.")
        except Exception as e:
            logger.error(f"Échec du test d'ouverture de compte : {str(e)}")
            raise

    @parameterized.expand([
        ("valid_code", 8888, 200),
        ("invalid_code", 0000, 400),
    ])
    def test_recharge_scenarios(self, name, code, expected_status):
        """Validation des scénarios de recharge"""
        # Logique de test pour les différents codes captcha
        pass

Étiquettes: Python BeautifulSoup requests unittest API-Testing

Publié le 1 novembre à 06h03