2017-01-30 49 views
0

我在围棋中实现的REST API如何嘲笑,我想测试一个处理函数,它看起来像下面同时使用中间人杜松子酒发送HTTP请求API

func editNameHandler(c *gin.Context) { 
     // make a ReST call to another server 
     callToAnotherServer() 
     c.Status(200) 
} 

我想嘲弄callToAnotherServer方法,以便我的测试用例根本不会调用第三方服务器。

我的测试用例看起来像

func TestSeriveIdStatusRestorePatch(t *testing.T) { 

    // Request body 
    send := strings.NewReader(`{"name":"Robert"}` 

    // this function sends an HTTP request to the API which ultimately calls editNameHandler 
    // Ignore the variables.The variables are retrieved in code this is to simplify question 
    ValidTokenTestPatch(API_VERSION+"/accounts/"+TestAccountUUID+"/students/"+TestStudentId, t, send, http.StatusOK)   
} 

我通过Mock functions in Go去其中提到,我们怎么能传递一个函数来嘲笑。我想知道如何在发送http请求时传递函数?我如何在这种情况下模拟功能。最佳做法是什么?

+1

请参阅https://godoc.org/net/http/httptest#Server –

回答

0

我不认为这个问题有单一的回应,但我会分享我的方法,我目前正在做的依赖注入Go-go-gin(但应该是几乎与任何其他路由器)。

从业务角度来看,我有一个结构体,它包含所有对我的服务的访问,这些服务负责业务规则/处理。

// WchyContext is an application-wide context 
type WchyContext struct { 
    Health services.HealthCheckService 
    Tenant services.TenantService 
    ... whatever 
} 

我的服务就是接口。

// HealthCheckService is a simple general purpose health check service 
type HealthCheckService interface { 
    IsDatabaseOnline() bool 
} 

有哪些多张的实现,如MockedHealthCheckPostgresHealthCheckPostgresTenantService等。

我的路由器不是取决于WchyContext,其代码如下所示:

func GetMainEngine(ctx context.WchyContext) *gin.Engine { 
    router := gin.New() 
    router.Use(gin.Logger()) 
    router.GET("/status", Status(ctx)) 
    router.GET("/tenants/:domain", TenantByDomain(ctx)) 
    return router 
}` 

StatusTenantByDomain行为像一个处理工厂,它的作用是创建一个基于给定的背景下,新的处理程序,像这样的:

type statusHandler struct { 
    ctx context.WchyContext 
} 

// Status creates a new Status HTTP handler 
func Status(ctx context.WchyContext) gin.HandlerFunc { 
    return statusHandler{ctx: ctx}.get() 
} 

func (h statusHandler) get() gin.HandlerFunc { 
    return func(c *gin.Context) { 
     c.JSON(200, gin.H{ 
      "healthy": gin.H{ 
       "database": h.ctx.Health.IsDatabaseOnline(), 
      }, 
      "now":  time.Now().Format("2006.01.02.150405"), 
     }) 
    } 
} 

正如你看到的,我的健康检查的处理程序并不关心具体落实我的服务,我只是用它无论是在ctx.

最后一部分取决于当前的执行环境。在自动化测试中,我创建一个新的WchyContext使用嘲笑/存根服务并将其发送到GetMainEngine,像这样:

ctx := context.WchyContext{ 
    Health: &services.InMemoryHealthCheckService{Status: false}, 
    Tenant: &services.InMemoryTenantService{Tenants: []*models.Tenant{ 
     &models.Tenant{ID: 1, Name: "Orange Inc.", Domain: "orange"}, 
     &models.Tenant{ID: 2, Name: "The Triathlon Shop", Domain: "trishop"}, 
    }} 
} 
router := handlers.GetMainEngine(ctx) 

request, _ := http.NewRequest(method, url, nil) 
response := httptest.NewRecorder() 
router.ServeHTTP(response, request) 
... check if response matches what you expect from your handler 

当你安装它去倾听一个HTTP端口,布线了这个样子的:

var ctx context.WchyContext 
var db *sql.DB 

func init() { 
    db, _ = sql.Open("postgres", os.Getenv("DATABASE_URL")) 

    ctx = context.WchyContext{ 
     Health: &services.PostgresHealthCheckService{DB: db}, 
     Tenant: &services.PostgresTenantService{DB: db} 
    } 
} 

func main() { 
    handlers.GetMainEngine(ctx).Run(":" + util.GetEnvOrDefault("PORT", "3000")) 
} 

有几件事我不喜欢这件事,我可能会在稍后重构/改进它,但它迄今运行良好。

如果你想看到完整的代码参考,我在做这个项目在这里https://github.com/WeCanHearYou/wchy

希望它可以帮助你以某种方式。