🔧 Programmierung 🕛 vor 1 Jahr 17 Min Lesezeit
0

Streamlined Contract Testing in Node.js: A Simple and Achievable Approach

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Do you want the benefits of contract testing with much less effort? Are you convinced of the benefits of contract testing but think it’s just too difficult to roll out across your organization?



You might worry that implementing Pact in your organization requires challenging changes to culture and process.



In this article, I’ll show you a drastically simplified approach to contract testing that a single developer can bring online. You'll get many of the benefits of contract testing for much less work. You'll build a platform that will help convince your team of how much contract testing can help prevent problems going out to production.



If you've ever tried to read the Pact documentation, you might think contract testing is a complicated team-based affair that requires new infrastructure. Let me show you that it doesn’t have to be this way.






Pre-requisites



.



JSON Placeholder is a fake REST API that includes endpoints for creating, updating, reading, and deleting “blog posts”. In Figure 1, you can see the JSON response for getting all blog posts.

Figure 1: The JSON response from JSON Placeholder getting all blog posts, viewed in Chrome.



We'll use the Jest testing framework to run our contract tests. The Axios code library will make HTTP requests to the JSON Placeholder REST API, then we’ll check that the responses conform to a contract defined in a JSON schema. The setup for our first example is illustrated in Figure 2:



for the first example project:




CODE
cd simplified-contract-testing/rest-api






Then install project dependencies:




CODE
npm install






Now run the tests:




CODE
npm test






After a few moments, you should see the output from a handful of successful tests.



Now let’s see how the code works. Listing 1 shows a pared-down version of the YAML test spec that makes a HTTP request to the /post endpoint and checks the response against the GetPostsResponse schema. .




CODE
const axios = require("axios");
const yaml = require("yaml");
const fs = require("fs");
const { resolveRefs } = require("./lib/resolver");

const { matchers } = require("jest-json-schema");
expect.extend(matchers);

// The REST API we are testing:
const baseURL = `https://jsonplaceholder.typicode.com`;

describe("Contract tests", () => {
// Loads the test spec:
const testSpec = resolveRefs(
yaml.parse(fs.readFileSync(`${__dirname}/test-spec.yaml`, "utf-8"))
);

// Generates a test for each contract test in the spec:
test.each(testSpec.specs)(`$title`, async (spec) => {
// Makes the HTTP request:
const response = await axios({
method: spec.method,
url: spec.url,
baseURL,
data: spec.body,
validateStatus: () => true, // All status codes are ok.
});

// Matches headers:
if (spec.expected.headers) {
for ([headerName, expectedValue] of Object.entries(
spec.expected.headers
)) {
const actualValue = response.headers[headerName.toLowerCase()];
expect(actualValue).toEqual(expectedValue);
}
}

// Matches response body against the expected schema:
if (spec.expected.body) {
expect(response.data).toMatchSchema(spec.expected.body);
}
});
});









Listing 2: Generating a Series of Jest Tests from Our Data



We have already seen how simple it can be to make data-driven contract tests against an existing REST API. Now let’s run our contract tests against a more realistic REST API backed by a database.






Mocking Your Database for Fast Contract Tests



To try out this second example for yourself, change into the .



You can see how this looks in Figure 3. Now we are running a REST API locally, and we have it talking to a mock database where we can control the data fixtures on a test-by-test basis:



can replace a real code module while automated tests run. So we place the file mongodb.js in the __mocks__ subdirectory, and Jest automatically replaces require(“mongodb”) with our mock version of the code. You can see in Listing 3. Note the new fixture field that, in this case, specifies that this test should load the data fixture named many-posts.




CODE
- title: Gets all blog posts
description: Gets all blog posts from the REST API.
# Specifies the data fixture to load before running the test:
fixture: many-posts
method: get
url: /posts
expected:
status: 200
headers:
Content-Type: application/json; charset=utf-8
body:
$ref: "#/schema/definitions/GetPostsResponse"









Listing 4: A Test That Loads the Data Fixture many-posts



What we are missing now is the code that loads the data fixture for each test, which you can see in Listing 5 — or , we will extend our REST API so that it can send and receive messages through a RabbitMQ instance. Try out the tests for yourself:




CODE
cd simplified-contract-testing/mocked-rabbit
npm install
npm test









Mocking Your Message Queue for Fast, Asynchronous Contract Tests



Please note that we are mocking RabbitMQ in this example, but in principle, this technique can work for any asynchronous messaging system (such as Kafka or SQS).



Let's mock the module amqplib (essentially RabbitMQ), so that we can:




  • Directly invoke asynchronous message handlers.

  • Retrieve asynchronous published messages.



You can see how this looks in Figure 4. Our Jest tests are now acting through our mock version of RabbitMQ to interact with our REST API:



.



The code that generates our contract testing suite is getting more complex, as you can see in Listing 8. Still, it’s not bad considering the number of tests and the different testing combinations that we can achieve with this relatively small piece of code. .




CODE
name: Automated contract tests

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
contract-tests:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3 # Installs Node.js.
with:
node-version: 20

- run: npm ci # Installs project dependencies.
- run: npm test # Runs the automated contract tests.









Listing 9: The GitHub Actions Workflow Runs Simplified Contract Tests for a Project



Back in the beginning of this article, I showed how we can run contract tests against an existing REST API. In the same way, we can run our contract tests against any REST API or service that we can access.



Because we control the code making the HTTP request, we can augment the code to include authentication details for the production deployment of our REST API and then run the contract tests against it. If you are contract testing against a production service via asynchronous messaging, then you'll need access (e.g., via an SSH tunnel or Kubernetes port forwarding) to your message queue.



Obviously, we must be very careful if we run contract tests against a production system, especially when tests can make changes to that system. In the full version of my example, you may have noticed that one of the tests makes an HTTP POST request to create a blog post in the REST API. Tests like this are probably best run against a QA or staging deployment, but if you really do want to run them against production, you might want a test account to easily flush out after running tests.






Bringing It Together: How I Applied Contract Testing



In my team, we used the simplified approach to contract testing covered in this post without making the team adopt any arduous processes. We integrated it into our usual automated testing process (in this example, running npm test in our CI pipeline), and we didn’t need any new infrastructure (like a contract broker) to bring all this together.



Mocking, while not specifically related to contract testing, proved essential in making it convenient and fast to run these tests. Contract testing is more on the level of integration testing in terms of how much code it can cover for the least amount of effort.



But because we mock certain external services (like the database and message queue), our contract tests can be much closer to unit tests in terms of performance. This makes it easy and fast to run our contract tests locally for frequent feedback while we make code changes to a REST API or microservice.






Wrapping Up



In this article, we've shown you that contract testing in Node.js can be as simple as defining a JSON schema and then using your favorite testing framework to check responses from REST APIs and asynchronous messaging.



Using this simplified approach to contract testing, you can get started very quickly and gain practical results that will help convince your team that contract testing is worthwhile.



Happy testing!



P.S. If you liked this post, .

Vollständiger Original-Artikel
Den kompletten Beitrag mit allen Details direkt auf dev.to lesen.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Deutschlandticket: Betrüger locken mit falschen Gewinnen
1 Quelle
Umbau von Rechenzentren im laufenden Betrieb
1 Quelle
Ofcom discovers issuing Online Safety Act fines is easier than collecting them
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Streamlined Contract Testing in Node.js: A Simple and Achievable Approach

Thematisch verwandte Begriffe: Streamlined, Contract, Testing, Nodejs · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...