This document describes the testing strategy and how to run tests for the LinkKeeper project.
The project uses a comprehensive testing strategy with multiple levels:
Located in the same packages as the code being tested (with _test.go suffix):
internal/user-service/repository/user_test.go- User repository testsinternal/user-service/usecase/user_test.go- User business logic testsinternal/user-service/transport/http/http_test.go- User HTTP handler testsinternal/api-service/repository/link_test.go- Link repository testsinternal/api-service/usecase/link_test.go- Link business logic tests
Located in tests/ directory:
tests/integration_test.go- End-to-end integration tests
# Run all tests
task test
# Run only unit tests
task test:unit
# Run only integration tests
task test:integration
# Run tests with coverage report
task test:coverage# Run all tests
go test ./...
# Run tests with verbose output
go test -v ./...
# Run tests with race detector
go test -v -race ./...
# Run only short tests (skip integration tests)
go test -v -short ./...
# Run tests with coverage
go test -v -coverprofile=coverage.out ./...
go tool cover -html=coverage.out# Run tests
task test
# Run tests with coverage
task test:coverage
# Run linters
task lint
# Format code
task fmtThe project uses the following testing libraries:
github.com/stretchr/testify- Assertions and mockingassert- Assertion functionsrequire- Required assertions that stop test on failuremock- Mocking framework
gorm.io/driver/sqlite- In-memory SQLite for testing databases
Install test dependencies:
go get github.com/stretchr/testify/assert
go get github.com/stretchr/testify/mock
go get github.com/stretchr/testify/requirefunc TestUserRepo_Create(t *testing.T) {
db := setupTestDB(t)
repo := NewUserRepo(db)
user := &userservice.UserModel{
TelegramID: 123456789,
Username: "testuser",
}
err := repo.Create(user)
assert.NoError(t, err)
assert.NotEqual(t, uuid.Nil, user.ID)
}type MockRepository struct {
mock.Mock
}
func (m *MockRepository) GetByID(id uuid.UUID) (*User, error) {
args := m.Called(id)
return args.Get(0).(*User), args.Error(1)
}
func TestUsecase(t *testing.T) {
mockRepo := new(MockRepository)
mockRepo.On("GetByID", mock.Anything).Return(&User{}, nil)
// Use mockRepo in your test
mockRepo.AssertExpectations(t)
}func TestIntegration_CreateAndGetUser(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration test in short mode")
}
// Setup services
// Make HTTP requests
// Assert responses
}- Unit Tests: Aim for >80% coverage
- Critical Paths: 100% coverage for authentication, data persistence
- Integration Tests: Cover main user flows
Check current coverage:
task test:coverageThe project uses GitHub Actions for CI. See .github/workflows/ci.yml.
The CI pipeline runs:
- Code formatting checks (
go fmt) - Static analysis (
go vet) - Linter checks (
golangci-lint) - All tests with race detector
- Build verification for all services
- Docker image builds (on main branch)
Run all CI checks locally before pushing:
task ci:localInstall pre-commit hooks to run checks before each commit:
task hooks:installThe hooks will:
- Format code automatically
- Run
go vet - Run
go mod tidy - Run unit tests
- Keep tests isolated - Each test should be independent
- Use table-driven tests - For testing multiple scenarios
- Name tests clearly -
TestFunctionName_Scenario_ExpectedResult - Mock external dependencies - Use interfaces and mocks
- Test error cases - Don't only test happy paths
- Clean up resources - Use
t.Cleanup()or defer - Use test fixtures - For complex test data
- Skip slow tests - Use
t.Skip()for integration tests in short mode
# Run only unit tests (skip integration)
go test -short ./...
# Run tests in parallel
go test -parallel 4 ./...# Run with race detector to find concurrency issues
go test -race ./...# Generate coverage profile
go test -coverprofile=coverage.out ./...
# View coverage in browser
go tool cover -html=coverage.out
# View coverage summary
go tool cover -func=coverage.out- Add benchmark tests for performance-critical code
- Add E2E tests with Docker Compose
- Add mutation testing
- Increase coverage to >85%
- Add performance regression tests