rom8726

rom8726 

Passionate about developing developer tools

0subscribers

3posts

testy: YAML-Based Functional Tests for Go HTTP APIs

If you've ever written functional tests for a Go HTTP server, you’ve probably found yourself stuck between two extremes:
 - Writing black-box tests with curl or Postman clones (slow, no debug, hard to maintain)
 - Writing verbose Go test code for every API call, mocking, assertions, cleanup, etc.
That’s why I created testy — a declarative testing framework for Go HTTP APIs, built on top of YAML and your actual http.Handler.
---
Why testy?
Here’s what makes testy different:
 - ✅ Declarative tests written in plain YAML
 - ✅ Real http.Handler execution — your actual app code, not a subprocess
 - ✅ Full PostgreSQL fixture support via pgfixtures
 - ✅ Powerful mocking, assertions, and SQL checks
 - ✅ Great for debugging and stepping through real code
---
Debug Your Tests Like Real Code
Because testy runs requests through your actual Go http.Handler, you can set breakpoints in your API handlers and run tests in your IDE’s debug mode (`go test -v -run <TestName>`).
This makes test runs feel like regular request handling — not like opaque black-box e2e scripts.
You don’t need to spin up your app on a port. testy hits your router directly — whether it’s from net/http, Gin, Chi, Echo or anything else.
---
Declarative Testing With YAML
Test scenarios are written as YAML lists of steps:
```yaml
- name: get_user
request:
method: GET
path: /users/123
response:
status: 200
json: |
{
"id": 123,
"name": "Alice"
}
```
No Go code. No boilerplate. Just requests and expectations.
---
Dynamic Placeholders and Context
testy supports smart templating:
 - {{step.response.field}} — reference values from earlier steps
 - {{ENV_VAR}} — use environment variables (like UUID, tokens, etc.)
 - Used in URLs, headers, bodies, SQL queries, everywhere
Example:
```yaml
- name: get user
request:
path: /users/{{create_user.response.id}}
```
---
Works with Your Real Code
A minimal Go test using testy looks like this:
```go
testy.Run(t, &testy.Config{
Handler: api.Router(), // your real app router
ConnStr: os.Getenv("TEST_DB"), // PostgreSQL
CasesDir: "./tests/cases", // YAML test cases
FixturesDir: "./tests/fixtures", // pgfixtures
})
```
That’s it.
You can run it with:
```bash
go test ./...
```
And debug it with your IDE as usual. Put a breakpoint in your handler — it just works.
---
Real-Life Example: Creating a Project
From `create.yml`:
```yaml
- name: create project with team
fixtures:
- empty_db
- developers_team
steps:
- name: login
request:
method: POST
path: /auth
body: {"username": "admin", "password": "Warden123!"}
response:
status: 200
- name: add_project
request:
method: POST
path: /projects/add
headers:
Authorization: "Bearer {{login.response.access_token}}"
body:
name: "Project With Team"
team_id: 1
response:
status: 201
dbChecks:
- query: SELECT name FROM projects WHERE team_id = 1
result:
- name: "Project With Team"
```
No test logic in Go. It’s all in the scenario.
---
Powered by pgfixtures
Each scenario can load fixtures into the DB before it starts — using pgfixtures.
Fixtures are described in YAML, and support:
 - Truncating tables
 - Resetting sequences
 - `$eval(SELECT ...)` expressions
```yaml
public.users:
- id: 1
name: "Alice"
created_at: $eval(SELECT NOW())
```
---
Mocks for Outgoing Requests
You can define HTTP mocks directly in the test file:
```yaml
mockServers:
notification:
routes:
- method: POST
path: /send
response:
status: 202
json: '{"status":"queued"}'
mockCalls:
- mock: notification
count: 1
expect:
method: POST
path: /send
body:
contains: "Joseph"
```
Mocks are verified and auto-spun for you. No third-party servers needed.
---
Highlights
 - Pure YAML: easily readable, editable by devs and QA alike
 - Real code path: debug API as usual — same context, same stacktrace
 - Built-in mocks: test integrations and verify outbound calls
 - DB fixtures & assertions: validate everything inside and out
 - Fast, IDE-friendly, minimal
---
Perfect for:
 - Testing REST API behavior end-to-end
 - Validating JSON responses and DB state
 - Reproducing edge cases and regression bugs
 - Debugging logic by stepping through real code paths
---
Try It Out
```bash
go get github.com/rom8726/testy@latest
```
Set up your test directory like:
```
/tests
├─ cases/ # YAML test scenarios
├─ fixtures/ # YAML DB fixtures
```
Then run `go test` — and debug away.
---
❤️ Open Source
testy is Apache-2.0 licensed and open to contributions.
If you like writing tests like a human, check it out:
👉 GitHub: github.com/rom8726/testy
Go up