英文:
Testing the values added in context in a request handler
问题
我有一个处理程序函数,它在请求上下文中添加一些键/值,并希望对其进行单元测试。我的测试代码如下:
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
body := strings.NewReader(tt.payload)
ctx := context.Background()
ctx = context.WithValue(ctx, http.ContextUserKey, http.Account{ID: accID.String()})
req, _ := nethttp.NewRequest("POST", "/api/groups/", body)
req = req.WithContext(ctx)
req.Header.Add("Content-Type", tt.contentType)
rr := httptest.NewRecorder()
router := mux.NewRouter()
router.HandleFunc("/api/groups/", s.HandlePostGroups(kc, es, mySQL)).Methods("POST")
router.ServeHTTP(rr, req)
if rr.Code != tt.status {
t.Errorf("wrong status code: got %v want %v", rr.Code, tt.status)
}
auditFields := req.Context().Value(http.AuditFields).(logrus.Fields)
// 我想要断言的是 Audit fields,它们是在请求处理程序函数中添加的
})
}
在处理程序函数内部,我像这样更新上下文:
func (s *IDMServer) HandlePostGroups(kc keycloak.API, es auth.KeyCreator, mySQL store.IDMRelationalStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// 在这里发生了很多事情,但是在代码的某个地方我这样做
if err != nil {
s.Log.WithField("error", err).Error("Unable to create key")
auditFields["event.outcome"] = "failure"
r = r.WithContext(context.WithValue(ctx, server.AuditFields, auditFields))
return
}
}
}
所以我设置了一个描述事件的上下文。但是在我的测试中,我得到了一个错误:
panic: interface conversion: interface {} is nil, not logrus.Fields [recovered]
panic: interface conversion: interface {} is nil, not logrus.Fields
因为该键不存在,返回的接口是nil。为什么上下文没有传播回测试函数?如何测试请求中的上下文?
英文:
I have a handler function that adds some key/values in the request context and wan to unittest it. My test is like this:
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
body := strings.NewReader(tt.payload)
ctx := context.Background()
ctx = context.WithValue(ctx, http.ContextUserKey, http.Account{ID: accID.String()})
req, _ := nethttp.NewRequest("POST", "/api/groups/", body)
req = req.WithContext(ctx)
req.Header.Add("Content-Type", tt.contentType)
rr := httptest.NewRecorder()
router := mux.NewRouter()
router.HandleFunc("/api/groups/", s.HandlePostGroups(kc, es, mySQL)).Methods("POST")
router.ServeHTTP(rr, req)
if rr.Code != tt.status {
t.Errorf("wrong status code: got %v want %v", rr.Code, tt.status)
}
auditFields := req.Context().Value(http.AuditFields).(logrus.Fields)
// Audit fields is what I want to assert. and are added in the request handler function
})
}
Inside the handler function I update the context like this:
func (s *IDMServer) HandlePostGroups(kc keycloak.API, es auth.KeyCreator, mySQL store.IDMRelationalStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// Many things happening here but somewhere in code I do this
if if err != nil {
s.Log.WithField("error", err).Error("Unable to create key")
auditFields["event.outcome"] = "failure"
r = r.WithContext(context.WithValue(ctx, server.AuditFields, auditFields))
return
}
}
}
So I set up a context to describe an event. But in my test I get a
panic: interface conversion: interface {} is nil, not logrus.Fields [recovered]
panic: interface conversion: interface {} is nil, not logrus.Fields
because the key does not exist and the interface returned is nil. Why isn't the context propagating back to the test function. And how can you test your context in a request?
答案1
得分: 1
r = r.WithContext(...)
更改了指针r。在这行代码之后,r指向一个新的请求。这个语句不会修改传入ServeHTTP的请求。
这回答了你的问题,为什么它不会向上游传播。
(我怀疑传播上下文更改到上游不是你应该尝试的事情。只需重新设计你的测试。)
英文:
r = r.WithContext(...)
changes r which is a pointer. After that line r points to a new request. The incoming request to ServeHTTP is unmodified by this statement.
This answers your question why it's not propagated upstream.
(I doubt propagating context changes upstream is something you should try. Just redesign your test.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论