Sind Sie ein QA-Tester und möchten in die Leistungstests eintauchen, ohne dass Sie über umfangreiche Programmierkenntnisse verfügen müssen? In diesem Artikel untersuchen wir eine für Nicht-Programmierer zugängliche Möglichkeit, mit Python eine Art Auslastungstest für Cloud-Apps-APIs durchzuführen. Lasttests ohne komplexe Codierung – entdecken Sie, wie selbst normale QA-Tester Python verwenden können, um schwerwiegende Fehler zu finden und potenzielle Leistungsengpässe aufzudecken.
Leistungstests sind ein entscheidender Aspekt, um sicherzustellen, dass Ihre Anwendungen realen Anforderungen gerecht werden. Ich werde versuchen, meinen Ansatz und Python-Skripte zu erläutern, die für den Lasttest eines Cloud-Dienstes zur Verwaltung von Browsern entwickelt wurden.
Lasttest-Szenario Stellen Sie sich einen Cloud-Dienst vor, der für die Verwaltung von Browserprofilen (Browser für Web-Scrapping) verantwortlich ist. Benutzer interagieren über die API mit dem Dienst, um Profile zu erstellen, zu starten, zu stoppen, zu löschen usw. Mein Python-Skript simuliert dieses Szenario und belastet den Cloud-Dienst, indem es diese Aktionen wiederholt ausführt.
# Dependencies import asyncio import httpx # Configuration API_HOST = 'https://cloud.io' API_KEY = 'qatest' API_HEADERS = { "x-cloud-api-token": API_KEY, "Content-Type": "application/json" } CYCLES_COUNT = 3 # Browser profile configuration data_start = { "proxy": "http://127.0.0.1:8080", "browser_settings": {"inactive_kill_timeout": 120} }
get_profiles
ruft vorhandene Browserprofile vom Dienst ab und simuliert ein Szenario, in dem Benutzer Informationen anfordern. async def get_profiles(cl: httpx.AsyncClient): resp = await cl.get(f'{API_HOST}/profiles', params={'page_len': 10, 'page': 0}, headers=API_HEADERS) return resp.json()
async def start_profile(cl: httpx.AsyncClient, uuid): resp = await cl.post(f'{API_HOST}/profiles/{id}/start', json=data_start, headers=API_HEADERS) if error := resp.json().get('error'): print(f'Profile {id} not started with error {error}')
async def stop_profile(cl: httpx.AsyncClient, uuid): resp = await cl.post(f'{API_HOST}/profiles/{id}/stop', headers=API_HEADERS) if error := resp.json().get('error'): print(f'Profile {id} not stopped with error {error}') async def delete_profile(cl: httpx.AsyncClient, uuid): resp = await cl.delete(f'{API_HOST}/profiles/{id}', headers=API_HEADERS) if error := resp.json().get('error'): print(f'Profile {id} not stopped with error {error}')
for conn in cl._transport._pool.connections: if conn._connection._state.value != 1: continue print(f'Connection in progress: {conn}')
Die Hauptfunktion orchestriert die Lasttestzyklen, iteriert durch Profile und führt asynchrone Aufgaben aus. Jeder Zyklus stellt eine simulierte Benutzerinteraktion dar, bei der Browserprofile erstellt, verwendet und gelöscht werden.
async def main(): async with httpx.AsyncClient(timeout=httpx.Timeout(timeout=300)) as cl: for _ in range(CYCLES_COUNT): profiles = await get_profiles(cl) start_tasks = [asyncio.create_task(start_profile(cl, profile['id'])) for profile in profiles] await asyncio.gather(*start_tasks) active_browsers = await get_active_profiles(cl) stop_tasks = [asyncio.create_task(stop_profile(cl, active_browser['id'])) for active_browser in active_browsers['data']] await asyncio.gather(*stop_tasks) profiles = await get_profiles(cl) del_tasks = [asyncio.create_task(delete_profile(cl, profile['id'])) for profile in profiles] await asyncio.gather(*del_tasks) # Monitor active connections for insights into load impact
Dieses Skript zeigt eine Grundlage für QAs, um Lasttestszenarien an ihre Anwendungen anzupassen. Durch Anpassen der Anzahl der Zyklen, Anpassen von Benutzerinteraktionen und Anpassen des Skripts an bestimmte API-Endpunkte können Tester wertvolle Einblicke in die Leistung ihrer Anwendung unter verschiedenen Lasten gewinnen. Hier benötigen Sie wichtige Überwachungstools, um Informationen über den Serverstatus zu erhalten, die Serverlast einzuschätzen und die Ressourcennutzung und Protokolle zu verfolgen. Nutzen Sie Tools wie Grafana, Kibana, Prometheus usw. für eine umfassende Überwachung. Behalten Sie außerdem die Antworten, die Ihr Skript erhält, genau im Auge, um eine gründliche Bewertung der Leistung Ihrer Anwendung sicherzustellen. Dieser Ansatz ist für Ihre effektiven Lasttests und Leistungsanalysen von unschätzbarem Wert.
Für eine realistischere Lastsimulation sollten Sie darüber hinaus in Betracht ziehen, bestimmte Seiten in Ihrem Browser zu öffnen. Während ich persönlich in meinen Browsern eine Startseite verwendet habe, können Sie auch Optionen wie Pyppeteer oder Playwright erkunden, um mehrere Registerkarten zu öffnen und durch verschiedene Seiten zu navigieren. Dieser Ansatz erhöht die Authentizität Ihres Lasttestszenarios und ähnelt stark den Benutzerinteraktionen mit Ihrer Anwendung.
# Attempt to connect to the browser using the provided profile URL try: browser = await connect({'browserWSEndpoint': browser_url, 'defaultViewport': None}) except Exception as e: # Handle connection errors and print a message print(f'Error occurred when connecting to the browser: {str(e)}') return # Create a new page in the connected browser page = await browser.newPage() # Introduce a brief delay to ensure the page is ready await asyncio.sleep(2) # Set the viewport dimensions for the page width, height = 1920, 1080 await page.setViewport({'width': width, 'height': height}) # Try to navigate to a specific URL try: await page.goto('https://{your_website}') # Wait for 10 seconds to simulate user interaction await page.waitFor(10000) # Introduce another delay for additional stability await asyncio.sleep(5) except pyppeteer.errors.PageError as e: # Handle page navigation errors and print a message print(f'Error occurred during page navigation: {str(e)}') # Attempt to take a screenshot of the page try: await page.screenshot(path='screen.png', fullPage=True) # Print a success message if the screenshot is captured successfully print('Screenshot taken successfully.') except Exception as e: # Handle screenshot capture errors and print a message print(f'Error occurred during taking a screenshot: {str(e)}')
Die asynchronen Funktionen von Python in Verbindung mit HTTP-Bibliotheken machen es zu einem vielseitigen Tool für Lasttests cloudbasierter Systeme. Dieses Beispiel dient als Ausgangspunkt für QA-Ingenieure, die die Leistungsfähigkeit von Python bei ihren Lasttestversuchen kennenlernen möchten.
NOTIZ
In meinem Szenario erwies sich das beschriebene Skript als robust und wirkungsvoll. Es diente als nützliches Instrument zur Identifizierung und Lösung zahlreicher Probleme. Der aggressive Charakter des Skripts war in Ordnung, um kritische Probleme zu lokalisieren, ein effektives Debugging zu ermöglichen und den Weg für eine nahtlose und verbesserte Benutzererfahrung zu ebnen, was für eine Qualitätssicherung ziemlich gut ist.
Im Folgenden werde ich kurz auf ein weiteres Skript eingehen, das das Multiprocessing-Modul von Python nutzt. Dieser Ansatz zielt darauf ab, die Lastgenerierung durch die gleichzeitige Ausführung mehrerer Instanzen des Testskripts zu verbessern. Das Hauptziel von Multiprocessing besteht darin, die Ausführung eines Skripts zu parallelisieren und gleichzeitige Interaktionen mit dem Dienst zu ermöglichen. Dieser Ansatz steht im Gegensatz zum zuvor diskutierten asynchronen Ansatz, bei dem Aufgaben nacheinander ausgeführt, aber gleichzeitig verwaltet werden. Dies ähnelt eher Spam/DDoS mit den gleichen Anfragen, könnte aber auch sehr nützlich sein.
def get_profiles(): response = requests.get(url=f"{api}", params=PARAMS, headers=headers) return response
def start_profiles(list_of_profiles_uuids): for uuid in list_of_profiles_uuids: # ... (API request to start profile) def stop_profiles(internal_uuids): for uuid in internal_uuids: # ... (API request to stop profile) def run_script(): start_profiles(get_profile_ids()) stop_profiles(list_of_ids)
if __name__ == "__main__": for runs in range(0, 5): processes = [] for i in range(20): p = multiprocessing.Process(target=run_script) processes.append(p) p.start() for p in processes: p.join()
Das Multiprocessing bietet eine Strategie für Auslastungstests von Anwendungen. Es ermöglicht QS-Ingenieuren, basierend auf den einzigartigen Eigenschaften ihrer Anwendungen mit verschiedenen Methoden zu experimentieren. Während asynchrone Tests eine Effizienz bei der Verwaltung gleichzeitiger Aufgaben bieten, zeichnet sich Multiprocessing durch die Parallelisierung des gesamten Testprozesses aus. Sie können den Ansatz wählen, der am besten zu Ihren spezifischen Lasttestzielen und Anwendungsanforderungen passt.
Eine kurze Erinnerung:
Diese Demo zielt darauf ab, grundlegende Konzepte in einem anfängerfreundlichen Format vorzustellen und die Einfachheit von Python für QS-Tester hervorzuheben, die sich an Leistungstests wagen.
Wenn Sie Programmierschwierigkeiten haben, zögern Sie nicht, zu googeln und Kollegen zu fragen, ChatGPT oder ähnliche Tools zu verwenden und GitHub Copilot für zusätzliche Unterstützung beim Schreiben Ihrer Lasttestskripte zu verwenden.
Auch hier veröffentlicht.