Comparison - TestlumFramework/Testlum GitHub Wiki
Testlum has a function of comparison.
This function implies comparing the expected result with the actual one after the step is completed.
To compare test results, the following files are used:
expected_n.json- expected test resultactual_n.json- actual test result
Having the structure expected_1.json, actual_1.json - the number is put, depending on the step of the test scenario.
Presence of
expectedfile is a mandatory parameter for HTTP, SQL and noSQL requests.
The principle of operation on the example of postgres:
<postgres comment="Check successfully adding Product to shopping cart" alias="Shop" file="expected_11.json"> <query> SELECT shp_cart_id, customer_id, shp_cart_code FROM shopping_cart WHERE merchant_id = 1 </query> </postgres>
- Make a request specifying the expected file (with the scenario step number, in this case
expected_11.json). - Create a file in the scenario folder with the name specified inside the postgres request (in this case,
expected_11.json). - Write to generated
expected_11.json-{}. - Run test scenario.
- After running the test scenario and executing this query, comparison will automatically generate an
actual_filewith the scenario step number, see an empty fileexpected_11.jsonand compare it with the query result received inactual_11.json. If the result of the request is satisfactory to the user, it will transfer all data from the actual file to the expected file, for further comparison and successful completion of the test scenario. -
comparison- will generate theactualfile only if the content betweenactualandexpecteddoes not match.
Testlum supports two modes for comparison. Let's dive deeper into strict and lenient comparison modes in Testlum.
Strict mode means everything must match exactly — including:
- All fields must be present.
- Order of elements (especially in arrays/lists) must match.
- Data types must be exactly the same.
- Values must be identical.
<http comment="Check ability to login added user with valid credentials" alias="MEGA_APP_BASIC"> <post endpoint="/basic/login"> <response code="200" file="expected_3.json" mode="strict"/> <header name="Authorization" data="Basic dGVzdGx1b"/> <body> <raw> { "username": "testlum", "password": "$2a$10$S" } </raw> </body> </post> </http>
Lenient mode is more forgiving:
- Extra fields are usually ignored.
- Order may not matter (especially in JSON objects or arrays).
- Minor type mismatches may be tolerated (e.g., "123" vs. 123).
- Only relevant or expected fields are compared.
<http comment="Check ability to login added user with valid credentials" alias="MEGA_APP_BASIC"> <post endpoint="/basic/login"> <response code="200" file="expected_3.json" mode="lenient"/> <header name="Authorization" data="Basic dGVzdGx1b"/> <body> <raw> { "username": "testlum", "password": "$2a$10$S" } </raw> </body> </post> </http>
✅ Tips:
strictmode is useful for verifying exact structure (e.g., schema validation).
lenientmode is better for checking essential correctness without enforcing formatting or extras.
strictis default mode for comparison in Testlum
| Feature | Strict Mode | Lenient Mode |
|---|---|---|
| Field presence | All fields must be present | Missing fields are tolerated |
| Field order | Must match exactly (especially for arrays) | Order can differ |
| Data type | Must match exactly (e.g., "123" vs 123 considered different) |
Minor mismatches allowed (e.g., "123" vs 123 considered equal) |
| Extra fields | Not allowed | Ignored |
| Default mode | ✅ Yes | ❌ No |
| Suitable for | Schema validation, exact structural match | Functional correctness without strict enforcement |
| Example usage | <response code="200" file="expected.json" mode="strict"/> |
<response code="200" file="expected.json" mode="lenient"/> |
Regular Expressions
While comparing
actualandexpectedfiles, some dynamical values might appear. For instance, in actual file with results of HTTP or SQL query (IDs, timestamp, etc). To avoid exception while comparison, you can use the following list of regular expression:
| Name | Pattern |
|---|---|
| p(any) | any sequence of any symbols |
| p(digit) | integer value (1,2,3,4,5...) |
| p(money) | float value (100.10, 532.83...) |
| p(email) | [email protected] |
| p(ip) | 10.10.10.10 |
| p(url) | http://google.com |
| p(uuid) | 550e8400-e29b-41d4-a716-446655440000 |
| p(color) | #1f1f1f |
| p(y-m-d) | 2015-11-12 |
| p(d-m-y) | 12-11-2015 |
| p(notEmpty) | any symbols but not empty |
Here is an example of using regular expressions in expected file:
{ "id": "p(digit)", "token": "p(any)" }
Also, we can set condition for our expected value. For instance:
| Condition | Description |
|---|---|
| c(>100) | any integer value more than 100 |
| c(>-111.11) | any float value more than -111.11 |
| c(<=145387) | any integer value lower than or equal to 145387 |
| c(>2001-02-16 20:00:00) | any timestamp after 2001-02-16 20:00:00 |
| c(<=now) | any timestamp before or equal to the current timestamp |
Symbols escaping
To use reserved symbols in scenario or json files, you need to escape them.
Here is the list of symbols you need to escape:
- "
- .
- *
- ^
- $
- ?
- +
- -
- {}
- []
- <>
- &
The way of symbol escaping depends on where you need to escape them. If you need to escape symbol in JSON file or in scenario, you need to follow the rules of escaping for specific format you're using (JSON, XML and so on).
So, here are some examples of symbol escaping for JSON and XML formats:
{ "query": "{ getBookByTitle(title: \"A Man Called Ove\") { id number } }" }<graphql comment="GraphQL query with invalid operationName for Get method" alias="spaceX"> <get endpoint="/graphql"> <response code="400" file="expected_6.json"/> <param name="query" data="query GetLaunchesByMissionName($missionName: String!) { launches(find:{ mission_name: $missionName }) { mission_name launch_date_local launch_success rocket {rocket_name rocket_type}}}"/> <param name="variables" data="{ "missionName": "CRS-16" }"/> <param name="operationName" data="GetLaunches"/> </get> </graphql>