A k6 extension for mocking HTTP(S) servers during test development. The design of the library was inspired by Express. If you already know Express framework, using this library should be very simple.
- Start mock HTTP server inside of a k6 process
- Familiar, Express like mock route definitions
- Almost transparent for test scripts: change import from
k6/http
tok6/x/mock/http
- Helps testing k6 tests with mock server
Table of Contents
This section contains an annotated, runnable k6 usage example script. You can extract the script with codedown and run with k6 using the following command line:
cat README.md | codedown javascript | k6 run -
Or you can simply download test/readme-usage.test.js
The k6/x/mock/http
module is a drop-in replacement for k6/http
module. During the k6 test development simply replace k6/http
imports with k6/x/mock/http
. Each URL's host and port part will be automatically replaced with the mock server's host and port value. Other parts of the request are remain untouched.
import http from "k6/x/mock/http";
The k6/x/mock
module's default export is an Express like default mock server with the usual HTTP method functions (get, head, post, put, ..) and use, function for defining middlewares.
You can add route definitions both in Init and VU stages.
import mock from "k6/x/mock";
mock.get("/question", (req, res) => {
res.json({ question: "How many?" });
});
function defaultMockExample() {
mock.get("/answer", (req, res) => {
res.json({ answer: 42 });
});
const question = http.get("https://question-api.server.url/question");
const answer = http.get("https://answer-api.server.url/answer");
console.log(question.body); // {"question":"How many?"}
console.log(answer.body); // {"answer":42}
}
With using the Server constructor you can create other mock server instances as well. Custom mock servers should start/stop manually. The server address can be get from addr()
function.
import { Server } from "k6/x/mock";
function customMockExample() {
const api = new Server()
.get("/custom", (req, res) => {
res.json({ foo: "bar" });
})
.start();
const res = http.get(`http://${api.addr()}/custom`);
console.log(res.body); // {"foo":"bar"}
api.stop();
}
export default function () {
defaultMockExample();
customMockExample();
}
API documentation can be found in docs/README.md.
This section contains an annotated, runnable k6 example script. You can extract the script with codedown and run with k6 using the following command line:
cat README.md | codedown js | k6 run -
Or you can simply download test/readme-example.test.js
-
Import mock and mock/http modules
import mock from "k6/x/mock"; import http from "k6/x/mock/http";
-
Import and setup Kahwah test runner
import { describe, it } from "https://cdn.jsdelivr.net/npm/kahwah"; export { options, default } from "https://cdn.jsdelivr.net/npm/kahwah";
-
Import
expect
from Chai Assertion Libraryimport { expect } from "cdnjs.com/libraries/chai";
-
Define mock routes
const users = { alice: { name: "alice", email: "[email protected]", }, }; mock.get("/user/{name}", (req, res) => { const user = users[req.params.name]; if (user) { res.json(user); } else { res.status(404); } }); mock.post("/user", (req, res) => { const user = req.body; if (user.name in users) { res.status(409); } else { users[user.name] = user; res.json(user); } });
-
Create tests
const base = "https://user-service.example.com"; describe("Get user", () => { it("existing user", () => { const res = http.get(`${base}/user/alice`); expect(res.status).equal(200); expect(JSON.parse(res.body).name).equal("alice"); }); it("missing user", () => { const res = http.get(`${base}/user/anonymous`); expect(res.status).equal(404); }); }); describe("Create user", () => { const options = { headers: { "Content-Type": "application/json" } }; it("new user", () => { const res = http.post(`${base}/user`, JSON.stringify({ name: "bob" }), options); expect(res.status).equal(200); expect(JSON.parse(res.body).name).equal("bob"); }); it("existing user", () => { const res = http.post(`${base}/user`, JSON.stringify({ name: "alice" }), options); expect(res.status).equal(409); }); });
The output of the test script will be something like this:
█ Get user ✓ existing user ✓ missing user █ Create user ✓ new user ✓ existing user
This section contains an annotated, runnable k6 example script to show how to organize mocks into separated file and make it easy to swith between mock server and real server version.
You can download the mock server version of the test from test/readme-best-practice-mock.test.js and the real server version from test/readme-best-practice.test.js. As you see, the only difference is the first import line.
-
Create separated
mock.js
module for mocking (download: test/mock.js)import mock from "k6/x/mock"; mock.get("/user", (req, res) => { res.json({ name: "alice", email: "[email protected]" }); });
-
Re-export
k6/x/mock/http
module contentexport { default } from "k6/x/mock/http"; export * from "k6/x/mock/http";
-
In test script, import
http
frommock.js
instead ofk6/http
import http from "./mock.js";
Switching from mock to real implementation as easy as replacing the line above with real
k6/http
module importimport http from "k6/http"
-
The other part of the test script is independent from mocking
import { describe, it } from "https://cdn.jsdelivr.net/npm/kahwah"; export { options, default } from "https://cdn.jsdelivr.net/npm/kahwah"; import { expect } from "cdnjs.com/libraries/chai"; describe("Get random user", () => { const res = http.get("https://phantauth.net/user"); it("200 OK", () => { expect(res.status).equal(200); }); const user = JSON.parse(res.body); it("name", () => { expect(user).to.have.property("name"); }); it("email", () => { expect(user).to.have.property("email"); }); });
The output of the test script will be something like this:
█ Get random user ✓ 200 OK ✓ name ✓ email
To build a k6
binary with this extension, first ensure you have the prerequisites:
- Go toolchain
- Git
Then:
- Install
xk6
:
$ go install go.k6.io/xk6/cmd/xk6@latest
- Build the binary:
$ xk6 build --with github.com/szkiba/xk6-mock@latest