Gitlab CI/CD: JAVA/Playwright

Grundlegende GitLab CI/CD & aqua Arbeitsablauf

Diese Anleitung zeigt, wie automatisiertes Testen in Ihre GitLab-CI/CD-Pipeline integriert wird, speziell unter Verwendung von Maven-Projekten mit JAVA/Playwright. Die Schritte können jedoch so angepasst werden, dass sie sich für jedes Testautomatisierungswerkzeug oder -framework eignen, um Ergebnisse an aqua zu übermitteln.

Voraussetzungen

  • Ein GitLab-Projekt mit aktiviertem CI/CD

  • ein aqua-Konto zum Einreichen von Testergebnissen

  • Eine Anwendung oder ein Projekt, das mit einem Maven-Projekt konfiguriert ist (z. B. unter Verwendung von Visual Studio Code).

Erstellen Sie zunächst ein sauberes Maven-Projekt oder verwenden Sie ein bestehendes.

Stellen Sie sicher, dass die folgenden Abhängigkeiten zur pom.xml Datei hinzugefügt werden. Wir benötigen die Playwright, JUnit und JSON-Bibliotheken.

Erstellen Sie eine TestBase-Klasse, um alle allgemeinen Methoden und Implementierungen der gemeinsamen Logik und Hooks zu speichern: _BeforeAll, BeforeEach, AfterAll, AfterEach, etc

Erstelle eine TestCase-Klasse, die die TestBase-Klasse erweitert und die tatsächliche Logik eines bestimmten Tests implementiert. Wir nehmen an, dass diese Klasse eine Aqua-Testfallinstanz hat, sodass wir ihre Ausführungsinformationen in der aqua-Webanwendung aktualisieren werden. Der TestCase hat einen Schritt (Schritt 1) in aqua.

Die TestFall-Klasse implementiert einfache Aktionen: öffnen www.wikipedia.org mit Playwright-Aktionen, klicken Sie dort ein paar Mal und überprüfen Sie die aktuelle Web-URL

Verwenden Sie den Hook @AfterEach in der TestBase-Klasse, um eine Verbindung zu Aqua herzustellen und ein Bearer-Token von einer REST-GET-Anfrage abzurufen, die von Playwright gesendet wird.

Der oben genannte Token wird für eine POST-Anfrage benötigt, um eine aqua-Testfalldurchführung zu erstellen. Wir verwenden den folgenden Endpunkt und das JSON.

Die Beispielimplementierung in der TestBase-Klasse für die obige Anforderung sieht wie folgt aus:

static void createTCExecution(TestInfo tcInfo, String status){ 

   Map<String, String> headers = new HashMap<>(); 

   headers.put("authorization", "Bearer " + bearerToken); 

   headers.put("content-type", "application/json"); 

   headers.put("accept", "application/json"); 

   headers.put("Connection", "keep-alive"); 

   

 

   APIRequestContext tcExecutionRequest = playwright.request().newContext(new APIRequest.NewContextOptions() 

     .setExtraHTTPHeaders(headers)); 

     

     JSONArray finalArr = new JSONArray(); 

     JSONObject json = new JSONObject(); 

 

     int tcId = Integer.parseInt(tcInfo.getTags().iterator().next()); 

 

 

     json.put("Guid", JSONObject.NULL); 

     json.put("TestCaseId", tcId); 

     json.put("TestCaseName", JSONObject.NULL); 

     json.put("Finalize", false); 

     json.put("ValueSetName", JSONObject.NULL); 

     json.put("TestScenarioInfo", JSONObject.NULL); 

     

     JSONArray stepsArr = new JSONArray(); 

     JSONObject jsonSteps = new JSONObject(); 

     

     jsonSteps.put("Index", 1); 

     jsonSteps.put("Name", "Step 1"); 

     jsonSteps.put("StepType", "Step"); 

     jsonSteps.put("Status", status); 

     jsonSteps.put("Description", JSONObject.NULL); 

     jsonSteps.put("ExpectedResults", JSONObject.NULL); 

     jsonSteps.put("ActualResults", JSONObject.NULL); 

     jsonSteps.put("ActualResultsLastUpdatedBy", JSONObject.NULL); 

     jsonSteps.put("ActualResultsLastUpdated","0001-01-01T00:00:00"); 

 

     stepsArr.put(jsonSteps); 

 

     json.put("Steps", stepsArr); 

     json.put("TestedVersion", JSONObject.NULL); 

     json.put("Status", JSONObject.NULL); 

     

      JSONObject execDuration = new JSONObject(); 

      execDuration.put("FieldValueType","TimeSpan"); 

      execDuration.put("Text","20 second"); 

      execDuration.put("Value",20); 

      execDuration.put("Unit","Second"); 

      

     json.put("ExecutionDuration", execDuration); 

     json.put("AttachedLabels", new JSONArray()); 

     json.put("CustomFields", new JSONArray()); 

     json.put("Attachments", JSONObject.NULL); 

     json.put("TesterId", JSONObject.NULL); 

     json.put("ExecutionDate", JSONObject.NULL); 

     json.put("AttachedFiles", new JSONArray()); 

 

     finalArr.put(json); 

 

     APIResponse tcExcutionResponse = tcExecutionRequest.post(appUrl + "api/TestExecution", RequestOptions.create().setData(finalArr.toString())); 

 

     assertTrue(tcExcutionResponse.ok()); 

 } 

Im obigen Antrag übergeben wir die Variable „logResult“. Sie stellt das tatsächliche JUnit-Testergebnis dar („Pass“, „Failed“, „NotRun“ usw.). Um diesen Status aus dem JUnit-Lauf zu erhalten, implementieren wir das Test Watcher Interface in der TestBase.

In dieser Klasse sollten wir Schnittstellenmethoden wie folgt implementieren:

@Override 

 public void testSuccessful(ExtensionContext context) { 

   System.out.println("Call Success extension"); 

   logResult = "Pass"; 

 } 

 

 @Override 

 public void testAborted(ExtensionContext context, Throwable cause) { 

   System.out.println("Call Abort extension"); 

   logResult = "NotRun"; 

 } 

 

 @Override 

 public void testFailed(ExtensionContext context, Throwable cause) { 

   System.out.println("Call Fail extension"); 

   logResult = "Failed"; 

 } 

Wir gehen davon aus, dass der Name der Testklasse auf der tatsächlichen aqua-Testfall-ID basiert: z. B. im obigen Fall haben wir den aqua-Testfall mit der Id=270 aktualisiert.

Nach erfolgreicher JUnit-Testausführung sollten wir die entsprechende einzelne Testfallausführung in aqua sehen. Diese ID-Variable kann aus der Testklasse über TestInfo von org.junit.jupiter.api.TestInfo übergeben werden.

Um das oben genannte Maven-Projekt mit GitLab CI/CD ausführen zu können, müssen wir die entsprechende Workflow-Datei .gitlab-ci.yml erstellen. Ein einfaches Beispiel für ein .gitlab-ci.yml-Skript ist unten gezeigt:

image: maven:latest 

 

stages:          

 - test 

 

maven-build-job:    

 stage: test     

 script: 

   - pwd  

   - sleep 10 

   - cd aqua-demo/ 

   - mvn compile 

   - mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" 

   - mvn clean test 

Sobald ein GitLab-Test-Runner konfiguriert und mit Ihren GitLab-Projekten verbunden ist, können wir die GitLab-Pipeline mit dem obigen Workflow ausführen:

Full TestBase class listing:

package com.aqua; 

 

import com.google.gson.Gson; 

import com.google.gson.JsonObject; 

import com.microsoft.playwright.APIRequest; 

import com.microsoft.playwright.APIRequestContext; 

import com.microsoft.playwright.APIResponse; 

import com.microsoft.playwright.Browser; 

import com.microsoft.playwright.BrowserContext; 

import com.microsoft.playwright.BrowserType; 

import com.microsoft.playwright.Page; 

import com.microsoft.playwright.Playwright; 

import com.microsoft.playwright.options.FormData; 

import com.microsoft.playwright.options.RequestOptions; 

 

import org.junit.jupiter.api.AfterAll; 

import org.junit.jupiter.api.AfterEach; 

import org.junit.jupiter.api.BeforeAll; 

import org.junit.jupiter.api.BeforeEach; 

import org.junit.jupiter.api.TestInfo; 

import org.junit.jupiter.api.extension.ExtensionContext; 

import org.junit.jupiter.api.extension.TestWatcher; 

import org.json.*; 

 

import static org.junit.jupiter.api.Assertions.assertTrue; 

 

import java.util.HashMap; 

import java.util.Map; 

 

public class TestBase implements TestWatcher 

{ 

 private static Playwright playwright; 

 private static Browser browser; 

 private static String appUrl = "https://aqua-auto-aqamasterpla.aqua-testing.com/aquawebng/"; 

 private static String bearerToken; 

 private static APIRequestContext request; 

 private static BrowserContext context; 

 private static TestInfo testInfo; 

 private static String logResult; 

 Page page; 

 

 static void getBearerToken() { 

   Map<String, String> headers = new HashMap<>(); 

   headers.put("content-type", "application/x-www-form-urlencoded"); 

 

   request = playwright.request().newContext(new APIRequest.NewContextOptions() 

     .setExtraHTTPHeaders(headers)); 

   APIResponse response = request.post(appUrl + "api/token", RequestOptions.create().setForm( 

     FormData.create() 

       .set("grant_type", "password") 

       .set("username","start") 

       .set("password","default"))); 

 

   assertTrue(response.ok()); 

 

   JsonObject j = new Gson().fromJson(response.text(), JsonObject.class); 

   bearerToken = j.get("access_token").getAsString(); 

 } 

 

 static void createTCExecution(TestInfo tcInfo, String status){ 

   Map<String, String> headers = new HashMap<>(); 

   headers.put("authorization", "Bearer " + bearerToken); 

   headers.put("content-type", "application/json"); 

   headers.put("accept", "application/json"); 

   headers.put("Connection", "keep-alive"); 

   

 

   APIRequestContext tcExecutionRequest = playwright.request().newContext(new APIRequest.NewContextOptions() 

     .setExtraHTTPHeaders(headers)); 

     

     JSONArray finalArr = new JSONArray(); 

     JSONObject json = new JSONObject(); 

 

     int tcId = Integer.parseInt(tcInfo.getTags().iterator().next()); 

 

 

     json.put("Guid", JSONObject.NULL); 

     json.put("TestCaseId", tcId); 

     json.put("TestCaseName", JSONObject.NULL); 

     json.put("Finalize", false); 

     json.put("ValueSetName", JSONObject.NULL); 

     json.put("TestScenarioInfo", JSONObject.NULL); 

     

     JSONArray stepsArr = new JSONArray(); 

     JSONObject jsonSteps = new JSONObject(); 

     

     jsonSteps.put("Index", 1); 

     jsonSteps.put("Name", "Step 1"); 

     jsonSteps.put("StepType", "Step"); 

     jsonSteps.put("Status", status); 

     jsonSteps.put("Description", JSONObject.NULL); 

     jsonSteps.put("ExpectedResults", JSONObject.NULL); 

     jsonSteps.put("ActualResults", JSONObject.NULL); 

     jsonSteps.put("ActualResultsLastUpdatedBy", JSONObject.NULL); 

     jsonSteps.put("ActualResultsLastUpdated","0001-01-01T00:00:00"); 

 

     stepsArr.put(jsonSteps); 

 

     json.put("Steps", stepsArr); 

     json.put("TestedVersion", JSONObject.NULL); 

     json.put("Status", JSONObject.NULL); 

     

      JSONObject execDuration = new JSONObject(); 

      execDuration.put("FieldValueType","TimeSpan"); 

      execDuration.put("Text","20 second"); 

      execDuration.put("Value",20); 

      execDuration.put("Unit","Second"); 

      

     json.put("ExecutionDuration", execDuration); 

     json.put("AttachedLabels", new JSONArray()); 

     json.put("CustomFields", new JSONArray()); 

     json.put("Attachments", JSONObject.NULL); 

     json.put("TesterId", JSONObject.NULL); 

     json.put("ExecutionDate", JSONObject.NULL); 

     json.put("AttachedFiles", new JSONArray()); 

 

     finalArr.put(json); 

 

     APIResponse tcExcutionResponse = tcExecutionRequest.post(appUrl + "api/TestExecution", RequestOptions.create().setData(finalArr.toString())); 

 

     assertTrue(tcExcutionResponse.ok()); 

 } 

 

 @BeforeAll 

 static void berforeAll() { 

   playwright = Playwright.create(); 

   browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setSlowMo(50)); 

 } 

 

 @AfterAll 

 static void closeBrowser() { 

   createTCExecution(testInfo, logResult); 

   context.close(); 

   playwright.close(); 

 } 

 

 @BeforeEach 

 void createContextAndPage(TestInfo testInfo) { 

   TestBase.testInfo = testInfo; 

   context = browser.newContext(); 

   page = context.newPage(); 

 } 

 @Override 

 public void testSuccessful(ExtensionContext context) { 

   System.out.println("Call Success extension"); 

   logResult = "Pass"; 

 } 

 

 @Override 

 public void testAborted(ExtensionContext context, Throwable cause) { 

   System.out.println("Call Abort extension"); 

   logResult = "NotRun"; 

 } 

 

 @Override 

 public void testFailed(ExtensionContext context, Throwable cause) { 

   System.out.println("Call Fail extension"); 

   logResult = "Failed"; 

 } 

 

 @AfterEach 

 void closeContext() { 

   getBearerToken(); 

   System.out.println("Aqua TC Id being executed: " + testInfo.getTags().iterator().next()); 

 } 

 

} 

 

Full Test Class listing:

package com.aqua; 

 

import static org.junit.jupiter.api.Assertions.assertEquals; 

 

import org.junit.jupiter.api.Tag; 

import org.junit.jupiter.api.Test; 

import org.junit.jupiter.api.TestInfo; 

import org.junit.jupiter.api.extension.ExtendWith; 

 

@ExtendWith(TestBase.class) 

public class TestCase270 extends TestBase{ 

 

   @Test 

   @Tag("270") 

   void shouldSearchWiki(TestInfo testInfo) { 

     page.navigate("https://www.wikipedia.org/"); 

     page.locator("input[name=\"search\"]").click(); 

     page.locator("input[name=\"search\"]").fill("playwright"); 

     page.locator("input[name=\"search\"]").press("Enter"); 

     assertEquals("https://en.wikipedia.org/wiki/Playwright", page.url()); 

     System.out.println("Test Case executed"); 

   } 

 

} 

Last updated