Umfassende Tests Ihrer Compute Anwendungen mit JavaScript

Testautomatisierung ist in der modernen Anwendungsentwicklung unerlässlich. Anwendungen, die auf Fastlys Edge-Computing-Plattform Compute entwickelt werden, bilden da keine Ausnahme. Entwickler können zwar bereits Tests für ihre Compute Anwendungen mit nutzerdefinierten Shell-Skripten durchführen, aber wir wollten ihnen eine bequemere und intuitivere Lösung bieten. Mit unserer neuen Bibliothek „Compute Application Testing“ können Sie Tests in JavaScript erstellen.

So einfach schreiben Sie neue Tests mit unserer Bibliothek:

describe('/user.json', () => {
it('returns 200 status and valid username', async () => {
const resp = await app.fetch('/user.json');
assert.strictEqual(resp.status, 200);
const data = await resp.json();
assert.ok(/^\w+$/.test(data.username));
});
});

In diesem Blogpost vergleichen wir das Testen mithilfe von Shell-Skripten mit der neuen Bibliothek „Compute Application Testing“, damit Sie, unabhängig von der Programmiersprache, in der Sie Ihre Compute Anwendung geschrieben haben, die beste Methode zum Testen Ihres Codes wählen können.


Automatisierte Tests kommen in der Softwareentwicklung zum Einsatz, um zu beweisen, dass der Code ordnungsgemäß funktioniert, und um sicherzustellen, dass Codeänderungen keine bestehenden Funktionen beeinträchtigen. In Kombination mit Strategien wie Continuous Delivery erleichtert dies Entwicklern die Erstellung und Bereitstellung zuverlässiger Software, damit Teams immer ein fertiges, qualitativ hochwertiges Produkt parat haben.

Es gibt verschiedene Arten von Tests: „Modultests“, bei denen die kleinsten abgrenzbaren Softwarekomponenten – häufig auf Funktions-, Klassen- oder API-Level – getrennt voneinander getestet werden. Bei „Integrationstests“ werden die Interaktionen zwischen den verschiedenen Komponenten der Software getestet und bei „End-to-End-Tests“ wird schließlich die gesamte Anwendung danach geprüft, ob bestimmte Inputs auch zu den erwarteten Outputs führen.

Es ist dabei wichtig, auf allen drei Ebenen zu testen. In diesem Post beschränken wir uns allerdings auf End-to-End-Tests als effektive Methode, um sicherzustellen, dass Ihre Fastly Compute Anwendung auch weiterhin die erwarteten Outputs generiert.

Funktionsweise von End-to-End-Tests für Compute Anwendungen

Fastly Compute führt in beliebigen Sprachen (darunter Rust, Go oder JavaScript) kompilierte WebAssembly Module über unser globales Edge-Server-Netzwerk aus. Für Entwicklungs- und Testzwecke bietet Fastly eine lokale Testumgebung für Compute an.

Aber wie sieht ein End-to-End-Test für eine Anwendung aus, die auf Fastly Compute läuft? Da Compute Anwendungen als HTTP-APIs bereitgestellt werden, besteht eine Möglichkeit darin, einen GitHub Actions Workflow zu erstellen, der die Compute Anwendung in der Testumgebung startet und anschließend ein Shell-Skript ausführt, das wiederum cURL-Befehle ausführt:

.github/workflows/tests.yaml (Auszug)

jobs:
curl-test:
name: Build Compute Edge service, and test with curl
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Fastly CLI
uses: fastly/compute-actions/setup@main
- name: Install Edge code dependencies
run: npm install
- name: Build and start Compute application
run: fastly compute serve > ./out.txt & (tail -f ./out.txt &) | grep -qF 'Listening on http://127.0.0.1:7676'
- name: Run tests
run: ./curl-tests/test.sh

./curl-tests/test.sh

#! /bin/bash
echo "test: returns 200 and the text \"Hello, World!\" for /"
OUTPUT=$(curl -vs "http://127.0.0.1:7676/" 2>&1)
grep -qF "200 OK" <<< "$OUTPUT" || { echo 'status not 200' ; exit 1; }
grep -qF "Hello, World!" <<< "$OUTPUT" || { echo 'unexpected response content' ; exit 1; }
echo "test: returns 200 and json including \"newField\": \"newValue\" for /json"
OUTPUT=$(curl -vs "http://127.0.0.1:7676/json" 2>&1)
grep -qF "200 OK" <<< "$OUTPUT" || { echo 'status not 200' ; exit 1; }
grep -qF "\"newField\":\"newValue\"" <<< "$OUTPUT" || { echo 'unexpected response content' ; exit 1; }

Auch wenn Shell-Skripten einiges an Text enthalten, stellen diese Tests sicher, dass Änderungen am Code weiterhin den erwarteten Output liefern.

In JavaScript geschriebene Tests

Viele Programmiersprachen, Plattformen und Communities bieten bessere Möglichkeiten, wie zum Beispiel die Verwendung von Frameworks, die speziell für das Schreiben und Ausführen von Tests entwickelt wurden.

Dasselbe Maß an Funktionalität wollten wir auch für Fastly Compute, um einfache Tests für einen Fastly Compute Service wie folgenden schreiben zu können:

it('returns 200 and the text "Hello, World!" for /', async () => {
const resp = await app.fetch('/');
assert.strictEqual(resp.status, 200);
assert.ok((await resp.text()).includes('Hello, World!'));
});
it('returns 200 and json including "newField": "newValue" for /json', async () => {
const resp = await app.fetch('/json');
assert.strictEqual(resp.status, 200);
const responseJson = await resp.json();
assert.strictEqual(responseJson['data']?.['newField'], 'newValue');
});

Aus diesem Grund haben wir „Compute Application Testing“ für JavaScript ins Leben gerufen – eine Bibliothek, die speziell für diesen Zweck gemacht ist.

HINWEIS: End-to-End-Tests funktionieren nur mit den Inputs und Outputs eines Programms. Deshalb können die Tests und die Compute App, auf die sie sich beziehen, in derselben oder in verschiedenen Sprachen geschrieben sein. Mit dieser Bibliothek lassen sich in JavaScript gezielt End-to-End-Tests für Ihre Compute Anwendung erstellen.

JavaScript ist in aller Munde und bietet ausgezeichnete Unterstützung für Webanfragen, natives Parsen von JSON, nützliche Funktionen wie reguläre Ausdrücke, Zugriff auf Datenstrukturen wie Objekte und Arrays und die Möglichkeit, eine umfangreiche Paketbibliothek auf npm zu nutzen. Aufgrund dieser Eigenschaften lag es für uns auf der Hand, End-to-End-Tests in JavaScript zu schreiben. Und da wir hier nur die Inputs und Outputs überprüfen, sind wir dabei von der Sprache der Compute Anwendung unabhängig.

„Compute Application Testing“ für JavaScript ist eine JavaScript Bibliothek, die auf npm unter @fastly/compute-testing verfügbar ist. Ihre Testanwendung läuft unter Node.js. Sie sollten also eine Testanwendung erstellen, die von Ihrer Compute Anwendung unabhängig ist. Dort können Sie Ihre Compute Anwendung als Entwicklungsabhängigkeit hinzufügen.

npm install --save-dev @fastly/compute-testing

Sehen wir uns nun also an, wie ein individueller Test aussehen würde.

Wenn Sie mit der standardmäßigen Testausführung in Node.js oder einer BDD-ähnlichen Testausführung wie Jest vertraut sind, sollte Ihnen dies bekannt vorkommen. Der Name des Testfalls lautet: „returns 200 and the text "Hello, World!" for /“. Dabei verwenden wir die Variable „app“, um einen Aufruf des Pfads „/“ der Compute Anwendung zu starten. Anschließend treffen wir Aussagen über den Statuscode und den Textinhalt der Antwort.

Sie fragen sich vielleicht, was es mit der Variable „app“ genau auf sich hat. Es handelt sich dabei um eine Instanz einer Compute Anwendung, genauer gesagt um eine Klasse, die es Ihnen ermöglicht, eine Instanz Ihrer Compute Anwendung in Ihrer lokalen Testumgebung auszuführen. Die Variable steht für eine Instanz der Compute Anwendung und wird wie folgt eingesetzt:

import { ComputeApplication } from '@fastly/compute-testing';
describe('Edge app', () => {
const app = new ComputeApplication();
before(async () => {
await app.start({
// Set 'appRoot' to the directory in which to start the app. This is usually
// the directory that contains the 'fastly.toml' file.
appRoot: path.join(__dirname, '..'),
});
});
after(async() => {
await app.shutdown();
});
// ...tests here
});

Wenn die Klasse instanziiert wird, ruft sie das Fastly CLI auf, um eine Instanz Ihrer Compute Anwendung unter appRoot zu erzeugen. Sobald diese Instanz aktiv ist, können Ihre Tests mit dem einfachen Aufruf „.fetch()“ Anfragen an sie senden. Da Sie dafür dieselben Parameter benötigen wie für die globale Fetch-Funktion, können Sie als ersten Parameter ein URL-Objekt, einen String oder ein Request-Objekt verwenden und beliebige Header definieren. Als Antwort erhalten Sie ein Response-Objekt, das Sie auf seinen Status, seine Header und seine Inhalte testen können. Und weil es sich dabei um ein Response-Objekt handelt, können Sie auch seine anderen nützlichen Funktionen nutzen, darunter die integrierte JSON Deserialisierung:

it('returns 200 and json including "newField": "newValue" for /json', async () => {
const resp = await app.fetch('/json');
assert.strictEqual(resp.status, 200);
const responseJson = await resp.json();
assert.strictEqual(responseJson['data']?.['newField'], 'newValue');
});

Es gibt auch noch viele weitere JavaScript Funktionen, mit denen Sie aussagekräftige Tests schreiben können. Mit „Request“ können Sie beispielsweise Daten im JSON Format, Formulardaten (mit „FormData“) und Streaming Blobs senden. Und weil Sie ein Response-Objekt zurückerhalten, können Sie auf natives Streaming und JSON Parsing zugreifen, was hilfreich für die Überprüfung von HTTP-Antworten ist.

Mit Node.js haben Sie natürlich auch Zugang zu allen Paketen auf npm: Wenn Sie ein HTML DOM parsen möchten, können Sie JSDOM nutzen. Benötigen Sie ein JSON Web Token (JWT)? Dann müssen Sie nur nach jsonwebtoken suchen. In diesem Blogpost verwenden wir den Test Runner von Node.js zusammen mit den Assertions von Node.js. Wenn Sie aber lieber ein anderes Test-Framework oder eine Assertion-Bibliothek wie Jest, Mocha oder Chai verwenden, die auf Node.js läuft, dann können Sie das ebenfalls tun. Ganz gleich, was Sie mit Ihrem Test bezwecken wollen: Wenn Sie Ihre Tests in JavaScript für Node.js schreiben, können Sie Ihr Ziel erreichen.

Für die Durchführung Ihrer Tests können Sie zum Beispiel folgenden GitHub Workflow verwenden:

.github/workflows/tests.yaml (Auszug)

jobs:
compute-testing-test:
name: Test Compute Edge service using compute-testing
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Fastly CLI
uses: fastly/compute-actions/setup@main
- name: Install Edge code dependencies
run: npm install
- name: Install Test code dependencies
working-directory: ./test
run: npm install
- name: Run tests
working-directory: ./test
run: npm test

Bei Ausführung dieses Workflows erhalten Sie Zugang zu Testnamen und einigen Statistiken in diesem übersichtlichen Format:

Compute Blog image 1

Einzelheiten zum Code und zu den Tests in diesem Beispiel erhalten Sie bei GitHub unter https://github.com/harmony7/compute-testing-demo.

Testen Sie Ihren eigenen Code

Das Schreiben von Tests in JavaScript ist eine gute Alternative zur Verwendung von Skripten. Auf npm können Sie ab sofort „Compute Application Testing“ für JavaScript herunterladen und ausprobieren. Entdecken Sie, wie einfach es ist, Tests für Ihre Compute Anwendungen zu erstellen und auszuführen und sie zu Ihren CI-Tests hinzuzufügen.

HINWEIS: @fastly/compute-testing ist ein Produkt von Fastly Labs. Die Nutzungsbedingungen finden Sie auf der Fastly Labs Website.

Weitere Informationen und Beispiele finden Sie auf unserer GitHub Projektseite.

Wir von Fastly möchten Ihnen Tools zur Verfügung stellen, die es Ihnen ermöglichen, mehr Code auf der Edge auszuführen und bei der Entwicklung dieses Codes Ihre bekannten und bewährten Tools zu nutzen. Wir freuen uns immer zu hören, wenn unsere Nutzer diese Tools hilfreich finden. Teilen Sie mit der Fastly Community, was Sie so entwickeln.

Katsuyuki Omuro
Senior Software Engineer, Developer Relations
Veröffentlicht am

Lesedauer: 5 Min.

Sie möchten sich mit einem Experten austauschen?
Sprechen Sie mit einem Experten
Diesen Beitrag teilen
Katsuyuki Omuro
Senior Software Engineer, Developer Relations

Katsuyuki („Kats“) Omuro ist ein in Japan tätiger Developer und Echtzeit-Web-Enthusiast aus dem Developer Relations Team. Er tüftelt Dinge leidenschaftlich gerne aus und teilt sein Wissen mit anderen, um sie beim Lernen und der Weiterentwicklung zu unterstützen.

Sie möchten loslegen?

Setzen Sie sich mit uns in Verbindung oder erstellen Sie einen Account.