go - 如何模拟 gin.Context?
问题描述
嗨,我一直在尝试模拟 gin.Context 但我无法让它工作我正在尝试他们在这个解决方案中所做的但它不适用于我的路由器这是我一直得到的错误
r.POST("/urls", urlRepo.CreateUrl)
cannot use urlRepo.CreateUrl (value of type func(c controllers.Icontext)) as gin.HandlerFunc value in argument to r.POSTcompilerIncompatibleAssign
这是我为稍后模拟而创建的接口以及我将在其中进行测试的方法
type Icontext interface {
BindJSON(obj interface{}) error
JSON(code int, obj interface{})
AbortWithStatus(code int)
AbortWithStatusJSON(code int, jsonObj interface{})
}
func (repository *UrlRepo) CreateUrl(c Icontext) {
var url models.Url
c.BindJSON(&url)
if !validators.IsCreateJsonCorrect(url) {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "Error format in Short or Full"})
return
}
err := repository.reposito.CreateUrl(repository.Db, &url)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err})
return
}
c.JSON(http.StatusOK, url)
}
代替
func (repository *UrlRepo) CreateUrl(c Icontext)
它是
func (repository *UrlRepo) CreateUrl(c *gin.Context)
解决方案
严格来说,您不能*gin.Context
以一种有意义的方式“模拟” a,因为它struct
具有未导出的字段和方法。
此外,您不能传递给r.POST()
类型不是 a 的函数gin.HandlerFunc
,定义为func(*gin.Context)
. 您的处理程序的类型CreateUrl(c Icontext)
根本不匹配。
如果您的目标是对 Gin 处理程序进行单元测试,那么您绝对不必模拟*gin.Context
. 您应该做的是在其中设置测试值。为此,您可以简单地使用gin.CreateTestContext()
并手动初始化其中的一些字段。更多信息 在这里。
如果出于某种其他原因,您的目标是提供一种功能的替代实现,*gin.Context
以便在您的处理程序中使用,您可以做的是使用您自己的替代方法定义您自己的类型并将其嵌入*gin.Context
其中。
在实践中:
type MyGinContext struct {
*gin.Context
}
func (m *MyGinContext) BindJSON(obj interface{}) error {
fmt.Println("my own BindJSON")
return m.Context.BindJSON(obj) // or entirely alternative implementation
}
// Using the appropriate function signature now
func (repository *UrlRepo) CreateUrl(c *gin.Context) {
myCtx := &MyGinContext{c}
var url models.Url
_ = myCtx.BindJSON(&url) // will also print "my own BindJSON"
// ...
// other gin.Context methods are promoted and available on MyGinContext
myCtx.Status(200)
}
但老实说,我不确定你为什么要覆盖*gin.Context
. 如果你想提供不同的绑定逻辑,甚至不同的渲染,你可以实现库已经暴露的接口。例如:
实现绑定:
c.ShouldBindWith()
binding.Binding
将您可以实现的接口作为第二个参数:
type MyBinder struct {
}
func (m *MyBinder) Name() string {
return "foo"
}
func (m *MyBinder) Bind(*http.Request, interface{}) error {
// stuff
return nil
}
func MyHandler(c *gin.Context) {
var foo struct{/*fields*/}
c.ShouldBindWith(&foo, &MyBinder{})
}
实现一个渲染器:
type MyRenderer struct {
}
type Render interface {
func (m *MyRenderer) Render(http.ResponseWriter) error {
// ...
return nil
}
func (m *MyRenderer) WriteContentType(w http.ResponseWriter) {
header := w.Header()
if val := header["Content-Type"]; len(val) == 0 {
header["Content-Type"] = "application/foo+bar"
}
}
func MyHandler(c *gin.Context) {
c.Render(200, &MyRenderer{})
}
推荐阅读
- python - Python Selenium send_keys ~ 如何发送高级 Unicode 字符
- python - 元组与生成器表达式。为什么性能翻转,序列越长?
- css - 为什么 google-chrome-devtools 通过 XPath 识别的元素数量少于通过 CssSelector 识别的元素数量
- c# - 在面板中生成时预制件的尺寸太小
- node.js - 如何在路由中获取完整的 url 作为参数
- r - 在 r 中使用 rvest 进行网页抓取以从网页中获取内部信息
- swift - 通过下拉刷新逐一获取行,想要在 viewdidload 上的整个数组
- javascript - 带有元音变音 (ü) 的域上的 location.href 报告不同的域
- javascript - 根据数组中的对象状态设置数组状态
- angular - 我们可以/如何通过 @ViewChild 以角度访问孙子组件吗