@@ -5,20 +5,24 @@ import (
55 "encoding/json"
66 "io"
77 "net/http"
8+ "net/http/httptest"
89 "os"
910 "strconv"
11+ "strings"
1012 "testing"
1113 "time"
1214
1315 "github.com/go-redis/redismock/v9"
1416 "github.com/stretchr/testify/assert"
1517 "github.com/stretchr/testify/require"
18+ "go.uber.org/mock/gomock"
1619
1720 "gofr.dev/pkg/gofr"
1821 "gofr.dev/pkg/gofr/config"
1922 "gofr.dev/pkg/gofr/container"
2023 "gofr.dev/pkg/gofr/datasource/redis"
2124 "gofr.dev/pkg/gofr/logging"
25+ "gofr.dev/pkg/gofr/service"
2226 "gofr.dev/pkg/gofr/testutil"
2327)
2428
@@ -140,7 +144,7 @@ func TestIntegration_SimpleAPIServer_Health(t *testing.T) {
140144 statusCode int
141145 }{
142146 {"health handler" , "/.well-known/health" , http .StatusOK }, // Health check should be added by the framework.
143- {"favicon handler" , "/favicon.ico" , http .StatusOK }, //Favicon should be added by the framework.
147+ {"favicon handler" , "/favicon.ico" , http .StatusOK }, // Favicon should be added by the framework.
144148 }
145149
146150 for i , tc := range tests {
@@ -180,3 +184,140 @@ func TestRedisHandler(t *testing.T) {
180184 assert .Nil (t , resp )
181185 require .Error (t , err )
182186}
187+
188+ // MockRequest implements the Request interface for testing
189+ type MockRequest struct {
190+ * http.Request
191+ params map [string ]string
192+ }
193+
194+ func (m * MockRequest ) HostName () string {
195+ if m .Request != nil {
196+ return m .Request .Host
197+ }
198+
199+ return ""
200+ }
201+
202+ func (m * MockRequest ) Params (s string ) []string {
203+ if m .Request != nil {
204+ return m .Request .URL .Query ()[s ]
205+ }
206+
207+ return nil
208+ }
209+
210+ func NewMockRequest (req * http.Request ) * MockRequest {
211+ // Parse query parameters
212+ queryParams := make (map [string ]string )
213+ for k , v := range req .URL .Query () {
214+ if len (v ) > 0 {
215+ queryParams [k ] = v [0 ]
216+ }
217+ }
218+
219+ return & MockRequest {
220+ Request : req ,
221+ params : queryParams ,
222+ }
223+ }
224+
225+ // Param returns URL query parameters
226+ func (m * MockRequest ) Param (key string ) string {
227+ return m .params [key ]
228+ }
229+
230+ // PathParam returns URL path parameters
231+ func (m * MockRequest ) PathParam (key string ) string {
232+ return ""
233+ }
234+
235+ // Bind implements the Bind method required by the Request interface
236+ func (m * MockRequest ) Bind (i any ) error {
237+ return nil
238+ }
239+
240+ // createTestContext sets up a GoFr context for unit tests with a given URL and optional mock container.
241+ func createTestContext (method , url string , mockContainer * container.Container ) * gofr.Context {
242+ req := httptest .NewRequest (method , url , nil )
243+ mockReq := NewMockRequest (req )
244+
245+ var c * container.Container
246+ if mockContainer != nil {
247+ c = mockContainer
248+ } else {
249+ c = & container.Container {Logger : logging .NewLogger (logging .DEBUG )}
250+ }
251+
252+ logger := c .Logger
253+
254+ return & gofr.Context {
255+ Context : req .Context (),
256+ Request : mockReq ,
257+ Container : c ,
258+ ContextLogger : * logging .NewContextLogger (req .Context (), logger ),
259+ }
260+ }
261+
262+ func TestHelloHandler (t * testing.T ) {
263+ // With name parameter
264+ ctx := createTestContext (http .MethodGet , "/hello?name=test" , nil )
265+ resp , err := HelloHandler (ctx )
266+ assert .NoError (t , err )
267+ assert .Equal (t , "Hello test!" , resp )
268+
269+ // Without name parameter
270+ ctx = createTestContext (http .MethodGet , "/hello" , nil )
271+ resp , err = HelloHandler (ctx )
272+ assert .NoError (t , err )
273+ assert .Equal (t , "Hello World!" , resp )
274+ }
275+
276+ func TestErrorHandler (t * testing.T ) {
277+ ctx := createTestContext (http .MethodGet , "/error" , nil )
278+
279+ resp , err := ErrorHandler (ctx )
280+ assert .Nil (t , resp )
281+ assert .Error (t , err )
282+ assert .Equal (t , "some error occurred" , err .Error ())
283+ }
284+
285+ func TestMysqlHandler (t * testing.T ) {
286+ mockContainer , mocks := container .NewMockContainer (t )
287+
288+ // Setup SQL mock to return 4
289+ mocks .SQL .ExpectQuery ("select 2+2" ).
290+ WillReturnRows (mocks .SQL .NewRows ([]string {"value" }).AddRow (4 ))
291+
292+ ctx := createTestContext (http .MethodGet , "/mysql" , mockContainer )
293+
294+ resp , err := MysqlHandler (ctx )
295+ assert .NoError (t , err )
296+ assert .Equal (t , 4 , resp )
297+ }
298+
299+ func TestTraceHandler (t * testing.T ) {
300+ mockContainer , mocks := container .NewMockContainer (t , container .WithMockHTTPService ())
301+
302+ // Redis expectations
303+ mocks .Redis .EXPECT ().Ping (gomock .Any ()).Return (nil ).Times (5 )
304+
305+ // HTTP service mock
306+ httpService := mocks .HTTPService
307+ mockResp := & http.Response {
308+ StatusCode : http .StatusOK ,
309+ Body : io .NopCloser (strings .NewReader (`{"data":"mock data"}` )),
310+ }
311+ httpService .EXPECT ().Get (gomock .Any (), "redis" , gomock .Any ()).Return (mockResp , nil )
312+
313+ // Attach service to container
314+ mockContainer .Services = map [string ]service.HTTP {
315+ "anotherService" : httpService ,
316+ }
317+
318+ ctx := createTestContext (http .MethodGet , "/trace" , mockContainer )
319+
320+ resp , err := TraceHandler (ctx )
321+ assert .NoError (t , err )
322+ assert .Equal (t , "mock data" , resp )
323+ }
0 commit comments