Writes Go unit tests for a single service in `internal/core/services/` following the project's table-driven pattern with mockery-generated mocks and testify assertions.
Write Go unit tests for a single service in internal/core/services/. Tests follow the project's table-driven pattern with mockery-generated mocks and testify assertions. After writing, verify by running go test.
Before starting, collect:
user_service, playlist_service).Read internal/core/services/<service_name>.go.
Identify:
ErrUserIDRequired).Read internal/core/ports/repository.go.
For each dependency used by the service, note:
UserRepository).Check internal/core/ports/ports_mocks/ for a generated mock file matching each required dependency interface.
If a mock file exists, proceed to Step 4.
If a mock file is missing, run:
go generate ./internal/core/ports/...
Confirm the mock file was created before proceeding.
Read internal/core/domain/ files for any domain structs returned or accepted by the service methods under test. Note field names and types.
For each method under test, define test cases covering:
Write internal/core/services/<service_name>_test.go.
Follow all conventions below.
Run:
go test ./internal/core/services/... -v -run Test
If the tests fail, diagnose and fix. Repeat until all tests pass.
| Element | Convention | Example |
|---|---|---|
| Test file | <source_file>_test.go | user_service_test.go |
| Function per method | Test<MethodName> | TestGetUserByID |
| Table case field — input param | input<ParamName> | inputUserID |
| Table case field — dependency response | <depName><MethodName>Resp | userRepoGetUserByIDResp |
| Table case field — dependency error | <depName><MethodName>Err | userRepoGetUserByIDErr |
| Table case field — call flag | shouldCall<DepName><MethodName> | shouldCallUserRepoGetUserByID |
| Table case field — call count | expected<DepName><MethodName>CallCount | expectedUserRepoGetUserByIDCallCount |
| Table case field — expected return | expected<ReturnType> | expectedUser |
| Table case field — expected error | expectedErr | expectedErr |
| Table case name field | testScenario | testScenario |
| Mock type | Mock<InterfaceName> (generated) | MockUserRepository |
<depName> is the variable name of the dependency in the service struct (e.g., userRepo, mailer, cache). It is not always a repository — use the actual dependency name.
Do not use generic field names like name, input, result, or error.
Use this template as the structural pattern. Replace all <...> placeholders with values specific to the service under test.
Key structural rules:
t.Parallel() on both the top-level test and each sub-test.Test<MethodName> function per service method; all cases live inside it.On(...)) is gated by the shouldCall* flag.require.Error / require.NoError before assert.* so the test stops early on unexpected nil/non-nil errors.AssertNumberOfCalls when the method should be called; use AssertNotCalled otherwise.When a service method calls more than one dependency, or calls the same dependency multiple times, add explicit fields for each call:
// fields
firstDep<MethodName>Resp <Type>
firstDep<MethodName>Err error
shouldCallFirstDep<MethodName> bool
expectedFirstDep<MethodName>CallCount int
secondDep<MethodName>Resp <Type>
secondDep<MethodName>Err error
shouldCallSecondDep<MethodName> bool
expectedSecondDep<MethodName>CallCount int
Set up and assert each independently inside the test loop.
ports_mocks/.go test verification step.