A Katalon Studio project demonstrating two testing scenarios as part of a technical assessment:
- RESTful API testing, where Katalon acts as both a producer (creates data via
POST) and a consumer (reads data viaGET). - Apache Kafka testing, where Katalon acts as a consumer, reading and validating a message published to a Kafka topic.
RestKafkaTest/
├── Test Cases/
│ ├── TC_Producer_CreateUser.groovy # REST API - producer role
│ ├── TC_Consumer_GetUser.groovy # REST API - consumer role
│ └── TC_Consumer_KafkaMessage.groovy # Kafka - consumer role
├── Test Suites/
│ ├── TS_RestApiTests # Runs both REST test cases
│ └── TS_KafkaTests # Runs the Kafka test case
├── Keywords/
│ └── com/test/kafka/KafkaKeywords.groovy # Custom keyword wrapping the Kafka Java client
├── Drivers/ # Kafka client jar + its dependencies
│ ├── kafka-clients-3.7.0.jar
│ ├── slf4j-api-1.7.36.jar
│ ├── lz4-java-1.8.0.jar
│ ├── snappy-java-1.1.10.5.jar
│ └── zstd-jni-1.5.5-1.jar
├── docker-compose.yml # Spins up a local single-node Kafka broker
├── build.gradle
└── README.md
To run this project from scratch, you need:
| Tool | Purpose | Notes |
|---|---|---|
| Katalon Studio | Runs the test cases | Free, tested on version 11.4.0 |
| Java JDK 8+ | Required by Katalon | Any recent JDK works |
| Docker Desktop | Runs a local Kafka broker | Requires WSL2 on Windows |
| Git | To clone this repo | — |
No API keys, accounts, or paid services are required. The REST API tests hit a free public test API (reqres.in), and Kafka runs entirely locally via Docker.
Both REST test cases target https://reqres.in, a free public API made for testing/practice purposes (no auth required).
What it does: Sends a POST request to create a new user resource. This represents the producer role — Katalon is the one generating and pushing new data into the system under test.
Request:
POST https://reqres.in/api/users
Content-Type: application/json
{"name": "morpheus", "job": "leader"}
Assertions:
- HTTP status code is
201 Created - Response body contains the same
nameandjobthat were sent - Response includes a generated
id(proving the resource was actually created server-side, not just echoed back)
Why these checks matter: verifying the status code confirms the API accepted the request; verifying the echoed fields confirms no data corruption happened in transit; verifying a new id was returned confirms a real resource was created, not just a validation pass.
What it does: Sends a GET request to retrieve an existing user resource. This represents the consumer role — Katalon is reading and validating data that already exists in the system, rather than creating it.
Request:
GET https://reqres.in/api/users/2
Assertions:
- HTTP status code is
200 OK - The returned
data.idmatches the ID requested (2) - The returned
data.emailfield is present and non-null
Why these checks matter: the status code confirms the resource exists and is reachable; matching the ID confirms we received the correct record, not a wrong/cached one; checking email is non-null confirms the response has the expected schema/shape, not just a bare success code.
Groups both test cases so they run together as a single suite, giving one pass/fail result for the whole "REST API" requirement of the assessment.
Katalon has no built-in Kafka support, so this project imports the official Apache Kafka Java client library directly and wraps it in a small custom keyword.
[docker-compose.yml] → starts a local Kafka broker (localhost:9092)
│
▼
[kafka-console-producer, run manually] → publishes ONE test message to "test-topic"
│
▼
[Katalon: KafkaKeywords.consumeOneMessage()] → connects as a Kafka consumer, polls the topic
│
▼
[TC_Consumer_KafkaMessage] → parses the message and asserts its contents
Katalon only ever plays the consumer role, per the assessment's requirement. The message it consumes is published independently, using Kafka's own command-line producer tool — simulating an external system that produces events onto the topic.
Runs a single-node Apache Kafka broker (v3.7.0) in KRaft mode, meaning it does not require a separate ZooKeeper container — simpler to spin up for a test environment. It exposes port 9092 so both the console tools and Katalon (running on the host machine) can connect to it at localhost:9092.
Before running the Katalon test, a topic named test-topic is created and a single JSON message is published to it:
{"orderId": "1001", "status": "CREATED"}This is done using Kafka's own console tools (kafka-topics.sh, kafka-console-producer.sh) directly inside the running container — see Section 6 below for exact commands.
A Groovy class annotated with Katalon's @Keyword, making it callable from any test case like a built-in keyword.
consumeOneMessage(topic, bootstrapServers, groupId, timeoutSeconds)What it does internally:
- Configures a standard Kafka
KafkaConsumerusing the Apache Kafka Java client (kafka-clientslibrary), pointing at the givenbootstrapServersandgroupId. - Sets
auto.offset.reset = earliest, so it reads from the start of the topic rather than only new messages (important since our test message was published before the consumer starts). - Subscribes to the topic and polls repeatedly (once per second) until either a message arrives or the timeout expires.
- Returns the message's value as a plain string (or
nullif nothing arrived in time), which the test case then parses as JSON.
This mirrors the pattern shown in Katalon's own official Kafka sample project.
What it does: Calls consumeOneMessage() to read the message that was seeded into test-topic, then validates its contents.
Assertions:
- A message was actually received (not
null) within 15 seconds - The message parses as valid JSON
orderIdequals"1001"statusequals"CREATED"
Why these checks matter: checking for null confirms the consumer successfully connected to the broker and found the topic (connection/config problems would show up here); the field-level assertions confirm the message wasn't corrupted or misrouted, and that Katalon is correctly deserializing what a real downstream consumer of this event stream would need to read.
Wraps the Kafka test case as its own suite, isolating the "Kafka" requirement of the assessment from the REST API suite.
cd RestKafkaTest
docker compose up -dConfirm it's running:
docker psdocker exec -it kafka /bin/bashInside the container:
/opt/kafka/bin/kafka-topics.sh --create --topic test-topic --bootstrap-server localhost:9092 --partitions 1 --replication-factor 1
/opt/kafka/bin/kafka-console-producer.sh --topic test-topic --bootstrap-server localhost:9092At the producer prompt, type this in one line and press Enter once, then Ctrl+C to exit:
{"orderId": "1001", "status": "CREATED"}
Then leave the container:
exitNote: if you re-run the Kafka test multiple times, either delete and recreate the topic (
kafka-topics.sh --delete ...) and republish a fresh message, or change thegroupIdargument passed toconsumeOneMessage()in the test case — Kafka consumer groups only re-read messages they haven't already committed an offset for.
- Open Katalon Studio → File > Open Project → select the cloned
RestKafkaTestfolder. - Katalon will pick up the External Libraries (the jars in
Drivers/) automatically from the project's saved settings.
- Run
Test Suites/TS_RestApiTestsfor the REST API scenario (2 test cases). - Run
Test Suites/TS_KafkaTestsfor the Kafka scenario (1 test case), while the Docker Kafka container from step 5.1–5.2 is still running.
Both suites should report all test cases as Passed.
reqres.inwas chosen for the REST API tests because it's a free, publicly available test API with no signup required, making the project immediately runnable by anyone without credentials.- Kafka in KRaft mode (no ZooKeeper container) was chosen to keep the local setup simpler and faster to start for a test environment — it is functionally equivalent to a ZooKeeper-based cluster for this test's purposes.
- The Kafka producer step is deliberately manual (via
kafka-console-producer.sh), not automated in Katalon, since the assessment specifies Katalon should act only as the consumer for the Kafka portion. - Kafka client dependency jars are committed directly into the
Drivers/folder (rather than resolved via a build tool at runtime) so the project runs immediately after cloning, without an extra dependency-resolution step.