Current section
Files
Jump to
Current section
Files
guides/testing.md
# Testing
Strategies for testing code that depends on the Amp SDK.
## Unit Tests (Mocked)
Since the SDK shells out to the Amp CLI, unit tests should not call the real CLI. Instead, test your code's handling of the SDK's return values.
### Testing with Known Responses
```elixir
defmodule MyApp.AmpClientTest do
use ExUnit.Case, async: true
alias AmpSdk.Types.{ResultMessage, ErrorResultMessage}
test "handles successful result" do
result = %ResultMessage{
result: "All tests pass",
duration_ms: 2000,
num_turns: 1,
is_error: false
}
assert result.result =~ "tests pass"
end
test "handles error result" do
error = %ErrorResultMessage{
error: "Permission denied",
duration_ms: 100,
is_error: true,
permission_denials: ["Bash"]
}
assert error.is_error
assert "Bash" in error.permission_denials
end
end
```
For management JSON fixtures such as `permissions_list/0` and `mcp_list/0`,
assert both the typed fields and the preserved `extra` payload so future CLI
fields remain non-breaking.
### Testing Message Parsing
```elixir
test "parses JSON line into typed struct" do
json = Jason.encode!(%{
type: "result",
subtype: "success",
session_id: "T-123",
is_error: false,
result: "done",
duration_ms: 500,
num_turns: 1
})
assert {:ok, %AmpSdk.Types.ResultMessage{result: "done"}} =
AmpSdk.Types.parse_stream_message(json)
end
```
## Integration Tests (Live)
Tag live tests with `@tag :live` and exclude them by default. SSH-backed smoke
tests should use a separate `:live_ssh` tag so local live CLI coverage and
remote transport coverage can be run independently:
```elixir
# test/test_helper.exs
ExUnit.start(exclude: [:live, :live_ssh])
```
```elixir
defmodule MyApp.AmpLiveTest do
use ExUnit.Case, async: false
@moduletag :live
@tag timeout: 60_000
test "executes a real prompt" do
assert {:ok, result} = AmpSdk.run(
"Reply with only: hello",
%AmpSdk.Types.Options{dangerously_allow_all: true}
)
assert String.contains?(String.downcase(result), "hello")
end
end
```
Run live tests:
```bash
mix test --include live
```
Run live SSH smoke tests with the shared core harness:
```bash
CLI_SUBPROCESS_CORE_LIVE_SSH=1 \
CLI_SUBPROCESS_CORE_LIVE_SSH_DESTINATION=<ssh-host> \
mix test --only live_ssh --include live_ssh
```
Those tests no longer skip when the remote `amp` binary is absent. They assert
either a successful remote run or a structured `:cli_not_found` / `:auth_error`
result so error-shape regressions stay covered.
## Testing Argument Building
The `AmpSdk.Stream.build_args/1` function is public for testing:
```elixir
test "builds correct CLI args" do
args = AmpSdk.Stream.build_args(%AmpSdk.Types.Options{
mode: "smart",
visibility: "private",
labels: ["ci"]
})
assert "--execute" in args
assert "--stream-json" in args
assert "--mode" in args
assert "--label" in args
end
```
## SDK Test Suite
```bash
# Run unit tests (mocked, fast)
mix test
# Run all tests including live CLI tests
mix test --include live
```