""" Test patterns extracted from Medical-App-Core. Patterns covered: - go-sqlmock + GORM mock DB setup helper - testify assert / require style - Success + error path table-driven tests - Fiber app.Test() for HTTP handler testing - Mock repository pattern (interface-based) - setupTestDB() helper function - ExpectBegin / ExpectQuery / ExpectCommit / ExpectRollback chain """ from __future__ import annotations from string import Template GO_VERSIONS = ["1.21", "1.22", "1.23", "1.24"] _SERVICE_TEST_TEMPLATE = Template("""\ go$go_version implementations_test // services/implementations/${entity_lower}_service_test.go // Pattern: sqlmock + GORM + testify — success and error paths // Observed in: Medical-App-Core/services/implementations/appointment_service_test.go package implementations_test import ( \t"errors" \t"testing" \t"time" \t"$module/services/contracts" \t"$module/services/implementations" \t"github.com/DATA-DOG/go-sqlmock" \t"github.com/google/uuid" \t"github.com/stretchr/testify/assert" \t"gorm.io/driver/postgres" \t"gorm.io/gorm" ) // setupTestDB creates an in-memory mock database for service tests. // Returns the GORM DB and the sqlmock controller for expectation setup. func setupTestDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock) { \tt.Helper() \tdb, mock, err := sqlmock.New() \tif err != nil { \t\tt.Fatalf("failed to create mock DB: %v", err) \t} \tgormDB, err := gorm.Open(postgres.New(postgres.Config{Conn: db}), &gorm.Config{}) \tif err != nil { \t\tt.Fatalf("failed to open GORM DB: %v", err) \t} \tt.Cleanup(func() { db.Close() }) \treturn gormDB, mock } // TestCreate_Success verifies that a valid DTO produces a non-nil UUID. func Test${entity}Service_Create_Success(t *testing.T) { \tdb, mock := setupTestDB(t) \tsvc := implementations.New${entity}Service(db) \tdto := contracts.${entity}DTO{ $dto_fields \t} \tnewID := uuid.New() \tmock.ExpectBegin() \tmock.ExpectQuery(`INSERT INTO "${table}" .* RETURNING "id"`). \t\tWithArgs( \t\t\tsqlmock.AnyArg(), // created_at \t\t\tsqlmock.AnyArg(), // updated_at \t\t\tnil, // deleted_at $mock_args \t\t\tsqlmock.AnyArg(), // id \t\t). \t\tWillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(newID)) \tmock.ExpectCommit() \tgotID, err := svc.Create(dto) \tassert.NoError(t, err) \tassert.Equal(t, newID, gotID) \tassert.NoError(t, mock.ExpectationsWereMet()) } // Test${entity}Service_Create_DBError verifies the service surfaces DB errors. func Test${entity}Service_Create_DBError(t *testing.T) { \tdb, mock := setupTestDB(t) \tsvc := implementations.New${entity}Service(db) \tdto := contracts.${entity}DTO{ $dto_fields \t} \tmock.ExpectBegin() \tmock.ExpectQuery(`INSERT INTO "${table}" .* RETURNING "id"`). \t\tWillReturnError(errors.New("connection refused")) \tmock.ExpectRollback() \tgotID, err := svc.Create(dto) \tassert.Error(t, err) \tassert.Equal(t, uuid.Nil, gotID) \tassert.NoError(t, mock.ExpectationsWereMet()) } // Test${entity}Service_FindBy${lookup_field}_NotFound verifies gorm.ErrRecordNotFound is surfaced. func Test${entity}Service_FindBy${lookup_field}_NotFound(t *testing.T) { \tdb, mock := setupTestDB(t) \tsvc := implementations.New${entity}Service(db) \tmock.ExpectQuery(`SELECT .* FROM "${table}"`). \t\tWithArgs("NOTEXIST", sqlmock.AnyArg()). \t\tWillReturnError(gorm.ErrRecordNotFound) \tresult, err := svc.FindBy${lookup_field}("NOTEXIST") \tassert.Error(t, err) \tassert.Nil(t, result) \tassert.NoError(t, mock.ExpectationsWereMet()) } """) _HTTP_HANDLER_TEST_TEMPLATE = Template("""\ go$go_version controllers_test // controllers/${entity_lower}_controller_test.go // Pattern: Fiber app.Test() for HTTP handler unit testing // Observed in: Medical-App-Core/utils/response_util_test.go package controllers_test import ( \t"bytes" \t"encoding/json" \t"net/http" \t"net/http/httptest" \t"testing" \t"$module/controllers" \t"github.com/gofiber/fiber/v2" \t"github.com/stretchr/testify/require" ) // mock${entity}Service implements contracts.${entity}ServiceContract for testing. type mock${entity}Service struct { \tcreateResult string \tcreateErr error } func (m *mock${entity}Service) CreateFromInput(input any) (any, error) { \treturn m.createResult, m.createErr } func Test${entity}Controller_Create_Success(t *testing.T) { \tapp := fiber.New() \tctrl := controllers.New${entity}Controller(&mock${entity}Service{ \t\tcreateResult: "test-uuid", \t}) \tapp.Post("/${entity_plural}", ctrl.Create${entity}) \tbody, _ := json.Marshal(map[string]any{ \t\t"organization_name": "Test Org", $request_fields \t}) \treq := httptest.NewRequest(http.MethodPost, "/${entity_plural}", bytes.NewReader(body)) \treq.Header.Set("Content-Type", "application/json") \tresp, err := app.Test(req, -1) \trequire.NoError(t, err) \trequire.Equal(t, http.StatusCreated, resp.StatusCode) \tvar result map[string]any \trequire.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) \trequire.Equal(t, "${entity} created successfully", result["message"]) } func Test${entity}Controller_Create_MissingField(t *testing.T) { \tapp := fiber.New() \tctrl := controllers.New${entity}Controller(&mock${entity}Service{}) \tapp.Post("/${entity_plural}", ctrl.Create${entity}) \t// Send empty body — required fields missing \treq := httptest.NewRequest(http.MethodPost, "/${entity_plural}", bytes.NewReader([]byte("{}"))) \treq.Header.Set("Content-Type", "application/json") \tresp, err := app.Test(req, -1) \trequire.NoError(t, err) \trequire.Equal(t, http.StatusBadRequest, resp.StatusCode) } func Test${entity}Controller_Create_InvalidJSON(t *testing.T) { \tapp := fiber.New() \tctrl := controllers.New${entity}Controller(&mock${entity}Service{}) \tapp.Post("/${entity_plural}", ctrl.Create${entity}) \treq := httptest.NewRequest(http.MethodPost, "/${entity_plural}", bytes.NewReader([]byte("not json"))) \treq.Header.Set("Content-Type", "application/json") \tresp, err := app.Test(req, -1) \trequire.NoError(t, err) \trequire.Equal(t, http.StatusBadRequest, resp.StatusCode) } """) _TABLE_DRIVEN_TEST_TEMPLATE = Template("""\ go$go_version utils_test // utils/response_util_test.go // Pattern: table-driven tests with Fiber app.Test() // Observed in: Medical-App-Core/utils/response_util_test.go package utils_test import ( \t"encoding/json" \t"net/http" \t"net/http/httptest" \t"testing" \t"$module/utils" \t"github.com/gofiber/fiber/v2" \t"github.com/stretchr/testify/require" ) func TestRespondWithJSON(t *testing.T) { \tru := &utils.JSONResponseUtil{} \ttests := []struct { \t\tname string \t\tcode int \t\tpayload any \t\twantStatus int \t\twantKey string \t}{ \t\t{ \t\t\tname: "200 ok with map payload", \t\t\tcode: http.StatusOK, \t\t\tpayload: map[string]string{"message": "ok"}, \t\t\twantStatus: http.StatusOK, \t\t\twantKey: "message", \t\t}, \t\t{ \t\t\tname: "201 created", \t\t\tcode: http.StatusCreated, \t\t\tpayload: map[string]string{"id": "abc-123"}, \t\t\twantStatus: http.StatusCreated, \t\t\twantKey: "id", \t\t}, \t\t{ \t\t\tname: "400 bad request", \t\t\tcode: http.StatusBadRequest, \t\t\tpayload: map[string]string{"error": "invalid input"}, \t\t\twantStatus: http.StatusBadRequest, \t\t\twantKey: "error", \t\t}, \t} \tfor _, tc := range tests { \t\tt.Run(tc.name, func(t *testing.T) { \t\t\tapp := fiber.New() \t\t\tapp.Get("/test", func(c *fiber.Ctx) error { \t\t\t\treturn ru.RespondWithJSON(c, tc.code, tc.payload) \t\t\t}) \t\t\treq := httptest.NewRequest(http.MethodGet, "/test", nil) \t\t\tresp, err := app.Test(req, -1) \t\t\trequire.NoError(t, err) \t\t\trequire.Equal(t, tc.wantStatus, resp.StatusCode) \t\t\trequire.Equal(t, "application/json", resp.Header.Get("Content-Type")) \t\t\tvar body map[string]any \t\t\trequire.NoError(t, json.NewDecoder(resp.Body).Decode(&body)) \t\t\t_, ok := body[tc.wantKey] \t\t\trequire.True(t, ok, "expected key %q in response", tc.wantKey) \t\t}) \t} } """) ENTITIES = [ dict( entity="Appointment", entity_lower="appointment", entity_plural="appointments", table="appointments", lookup_field="Status", dto_fields='\t\tOrganizationID: uuid.New(),\n\t\tPatientID: uuid.New(),\n\t\tDoctorID: uuid.New(),\n\t\tDateTime: time.Now(),\n\t\tStatus: "scheduled",', mock_args='\t\t\tsqlmock.AnyArg(), // organization_id\n\t\t\tsqlmock.AnyArg(), // patient_id\n\t\t\tsqlmock.AnyArg(), // doctor_id\n\t\t\tsqlmock.AnyArg(), // date_time\n\t\t\t"scheduled", // status', request_fields='\t\t"patient_name": "João Silva",\n\t\t"doctor_full_name": "Dr. Maria",\n\t\t"specialization": "Cardiology",\n\t\t"date_time": "2024-03-01T10:00:00Z",', ), dict( entity="Patient", entity_lower="patient", entity_plural="patients", table="patients", lookup_field="CPF", dto_fields='\t\tOrganizationID: uuid.New().String(),\n\t\tName: "João Silva",\n\t\tContact: "+55 11 99999-9999",', mock_args='\t\t\tsqlmock.AnyArg(), // organization_id\n\t\t\t"João Silva", // name\n\t\t\t"+55 11 99999-9999", // contact', request_fields='\t\t"name": "João Silva",\n\t\t"contact": "+55 11 99999-9999",', ), ] class TestPatternGenerator: """Generate test pattern training examples.""" MODULE = "medical-sas-api" def all_examples(self) -> list[str]: examples: list[str] = [] for ent in ENTITIES: for ver in GO_VERSIONS: examples.append( _SERVICE_TEST_TEMPLATE.substitute(go_version=ver, module=self.MODULE, **ent) ) examples.append( _HTTP_HANDLER_TEST_TEMPLATE.substitute(go_version=ver, module=self.MODULE, **ent) ) for ver in GO_VERSIONS: examples.append(_TABLE_DRIVEN_TEST_TEMPLATE.substitute(go_version=ver, module=self.MODULE)) return examples