name: typespec-go-add-spector-test
description: Adds a Spector mock API test for the typespec-go emitter. Use when given a Spector case link (http-specs or azure-http-specs) to generate the Go client, add it to tspcompile.js, write *_client_test.go tests, and validate them against the Spector mock server.
Adding a Spector test for typespec-go
Inputs
You will receive a Spector case link pointing to a specific scenario/case under:
https://github.com/microsoft/typespec/tree/main/packages/http-specs/specs/...https://github.com/Azure/typespec-azure/tree/main/packages/azure-http-specs/specs/...
Output
- An entry added to
packages/typespec-go/.scripts/tspcompile.jsin the appropriate spec group (httpSpecsGrouporazureHttpSpecsGroup). - Generated Go client code under
packages/typespec-go/test/http-specs/orpackages/typespec-go/test/azure-http-specs/. - Hand-written
*_client_test.gofiles that validate the generated SDK against the Spector mock API server. One test file per generated client (i.e., perzz_<name>_client.gofile).
Workflow (copy as checklist)
- Ensure prerequisites are met (
pnpm install, package build) - Identify the Spector case link and determine spec type (http-specs vs azure-http-specs)
- Choose a group name and add the entry to
tspcompile.js - Run
pnpm tspcompile --filter=<groupname>to generate Go client code - Read the
mockapi.tsfile to understand expected request/response - Write one
*_client_test.gotest file per generated client, matching the mock API expectations - Start the Spector mock server (
pnpm spector --start) - Run the tests and verify they pass
- Stop the Spector mock server (
pnpm spector --stop)
Prerequisites — Environment setup
Before starting, ensure the build environment is ready.
All commands below run from the repo root (autorest.go/).
- Install dependencies:
pnpm install - Build the typespec-go package:
cd packages/typespec-go pnpm build
Step 1 — Identify the Spector case and spec type
Determine the spec type from the link
If the link is under
microsoft/typespec/.../packages/http-specs/specs/<path>:- Spec type = http-specs
- The entry goes into
httpSpecsGroupintspcompile.js - The spec input path is
<path>(relative to thehttp-specs/specs/root) - Generated output goes under
packages/typespec-go/test/http-specs/
If the link is under
Azure/typespec-azure/.../packages/azure-http-specs/specs/<path>:- Spec type = azure-http-specs
- The entry goes into
azureHttpSpecsGroupintspcompile.js - The spec input path is
<path>(relative to theazure-http-specs/specs/root) - Generated output goes under
packages/typespec-go/test/azure-http-specs/
Extract the spec path
From the link, extract the path after specs/. For example:
- Link:
https://github.com/microsoft/typespec/tree/main/packages/http-specs/specs/type/model/empty - Spec path:
type/model/empty
Check if the case already exists
Search tspcompile.js for the spec path. If it already exists, skip to Step 4 (writing tests).
Step 2 — Add the entry to tspcompile.js
Open packages/typespec-go/.scripts/tspcompile.js and add a new entry to the appropriate group object.
Entry format
'<groupname>': ['<spec-path>', '<optional-emitter-options>...'],
Naming conventions
Group name: lowercase, no hyphens, append
groupsuffix. Derived from the last segment of the spec path.type/model/empty→emptygroupazure/core/basic→basicgroupencode/datetime→datetimegroupazure/client-generator-core/access→accessgroup
Spec path: the path relative to the specs root (e.g.,
type/model/empty,azure/core/basic).
Example additions
For http-specs:
const httpSpecsGroup = {
// ... existing entries ...
'bytesgroup': ['encode/bytes'],
};
For azure-http-specs:
const azureHttpSpecsGroup = {
// ... existing entries ...
'basicgroup': ['azure/core/basic'],
};
Alphabetical ordering
Insert the new entry in a logical position (typically alphabetical by group name or grouped with related specs).
Step 3 — Generate the Go client code
From the packages/typespec-go directory, run:
pnpm tspcompile --filter=<groupname>
For example:
pnpm tspcompile --filter=emptygroup
This generates Go files (prefixed zz_) into the output directory under test/http-specs/ or test/azure-http-specs/.
Verify generation succeeded
Check that the output directory was created and contains generated files:
zz_*_client.go— client implementationzz_models.go— model typeszz_options.go— options structszz_responses.go— response typesgo.mod— Go module file
If the output directory is empty or missing zz_ files, generation failed. Check the console output for errors.
Initialize go.sum
After generation, you need to ensure go.sum is populated. From the generated module directory:
cd test/<http-specs|azure-http-specs>/<path>/<groupname>
go mod tidy
Step 4 — Read the mockapi.ts to understand expectations
The mockapi.ts file defines the expected HTTP requests and responses for each scenario. It is located at:
- For http-specs:
packages/typespec-go/node_modules/@typespec/http-specs/specs/<spec-path>/mockapi.ts - For azure-http-specs:
packages/typespec-go/node_modules/@azure-tools/azure-http-specs/specs/<spec-path>/mockapi.ts
Key elements in mockapi.ts
Each scenario entry contains:
uri— the HTTP endpoint pathmethod— HTTP method (get, post, put, patch, delete)request— expected request details:body— request body (wrapped injson(...))headers— expected request headersquery— expected query parameterspathParams— expected path parameters
response— what the mock server returns:status— HTTP status codebody— response body (wrapped injson(...))headers— response headers
Map scenarios to SDK methods
The scenario names follow a pattern like Type_Model_Empty_getEmpty which maps to the generated client method GetEmpty. Use the generated zz_*_client.go files to find the exact method signatures.
Step 5 — Write the test files
Create one *_client_test.go file per generated client. Each generated zz_<name>_client.go should have a corresponding <name>_client_test.go test file.
File structure and conventions
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
package <groupname>_test
import (
"context"
"<groupname>"
"testing"
"github.com/stretchr/testify/require"
)
Client construction
All generated clients have a New<ClientName>WithNoCredential constructor. Always use http://localhost:3000 as the endpoint:
client, err := <groupname>.New<ClientName>WithNoCredential("http://localhost:3000", nil)
require.NoError(t, err)
Test function naming
- Follow the pattern
Test<ClientName>_<MethodName>orTest<ClientName><MethodName>:TestEmptyClientGetEmptyTestBasicClient_CreateOrReplaceTestHeaderClientDefault
Sub-clients
If the generated code has sub-clients (e.g., NewBytesHeaderClient()), access them via the parent client:
client, err := bytesgroup.NewBytesClientWithNoCredential("http://localhost:3000", nil)
require.NoError(t, err)
resp, err := client.NewBytesHeaderClient().Base64(context.Background(), []byte("test"), nil)
Assertion patterns
- No response body (204): Use
require.Zero(t, resp) - Response with body: Use
require.EqualValues(t, expected, resp.<Field>) - Pointer fields: Use
to.Ptr(value)fromgithub.com/Azure/azure-sdk-for-go/sdk/azcore/to - Time values: Use
require.WithinDuration(t, expected, actual, 0) - Pager results: Iterate with
pager.More()/pager.NextPage(context.Background()) - LRO (Long-Running Operations): Use
poller.PollUntilDone(context.Background(), nil)
Common imports
import (
"context"
"<groupname>"
"testing"
"github.com/Azure/azure-sdk-for-go/sdk/azcore" // for azcore.ETag, etc.
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to" // for to.Ptr()
"github.com/stretchr/testify/require" // for assertions
)
Complete example
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
package emptygroup_test
import (
"context"
"emptygroup"
"testing"
"github.com/stretchr/testify/require"
)
func TestEmptyClientGetEmpty(t *testing.T) {
client, err := emptygroup.NewEmptyClientWithNoCredential("http://localhost:3000", nil)
require.NoError(t, err)
resp, err := client.GetEmpty(context.Background(), nil)
require.NoError(t, err)
require.Zero(t, resp)
}
func TestEmptyClientPutEmpty(t *testing.T) {
client, err := emptygroup.NewEmptyClientWithNoCredential("http://localhost:3000", nil)
require.NoError(t, err)
resp, err := client.PutEmpty(context.Background(), emptygroup.EmptyInput{}, nil)
require.NoError(t, err)
require.Zero(t, resp)
}
Step 6 — Start the Spector mock server and run tests
Start the Spector server
From the packages/typespec-go directory:
pnpm spector --start
This starts the Spector mock server in the background on http://localhost:3000. It serves both http-specs and azure-http-specs scenarios.
Run the tests
Navigate to the generated module directory and run the tests:
cd test/<http-specs|azure-http-specs>/<path>/<groupname>
go test -v ./...
For example:
cd test/http-specs/type/model/emptygroup
go test -v ./...
Verify all tests pass
All tests should pass. If a test fails:
- Check the mock server is running —
pnpm spector --startshould have been run first. - Check the endpoint URL — must be
http://localhost:3000. - Check the mockapi.ts — ensure the test matches the expected request/response exactly.
- Check generated code — read
zz_*_client.goto verify method signatures and parameter types. - Fix and re-run — iterate until all tests pass.
Stop the Spector server
After tests pass, stop the server:
pnpm spector --stop
Notes
- Each test group directory is a standalone Go module with its own
go.mod. - Generated files are prefixed with
zz_and should NOT be manually edited. - Test files (
*_client_test.go) are hand-written and ARE committed to the repo. - The
go.mod,go.sum, andLICENSE.txtfiles in the test directory are auto-generated. - The
testdata/_metadata.jsonfile tracks emitter version (normalized to"0.0.0"by the build script). - Do NOT edit
zz_version.go— it is preserved across regenerations for v2+ major version scenarios. - The mock server runs on
http://localhost:3000— all test clients must use this as the endpoint. - Use
requirefromgithub.com/stretchr/testifyfor all assertions (neverassert). - There are no shared test utility packages — each test module is fully self-contained.
- Create one test file per generated client: for each
zz_<name>_client.go, create a corresponding<name>_client_test.go. Do NOT consolidate all tests into a single file. - Only commit: test files (
*_client_test.go) and changes totspcompile.js. Generatedzz_*files,go.mod,go.sum,LICENSE.txt, andtestdata/are also committed (they are NOT gitignored for typespec-go tests). - When adding options to
tspcompile.js, fixed options (module,emitter-output-dir,file-prefix) cannot be overridden. Default options (generate-fakes,inject-spans,head-as-boolean,fix-const-stuttering) can be overridden per test.