如何测试/重构测试调用http.ListenAndServe的函数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何测试/重构测试调用http.ListenAndServe的函数相关的知识,希望对你有一定的参考价值。
我正在学习并正在研究一种简单的服务,它从队列中提取一些数据并将其粘贴到数据库中。它还运行Web服务器以允许抓取数据。现在我有两个go文件(为简洁起见省略了一些文字):
func main() {
parseConfig()
s := &Service{ServiceConfig: config}
err := s.Run()
if err != nil {
panic(err)
}
}
然后是服务的定义(为了简洁再次省略了一些部分):
func (s *Service) Run() error {
if err := s.validate(); err != nil {
return err
}
if err := s.initDB(); err != nil {
return err
}
defer s.db.Close()
// Same pattern with health check library (init, start, close)
// Same pattern starting queue consumer (init, start, close)
s.mux = http.NewServeMux()
s.registerHandlers(s.mux)
http.ListenAndServe(":8080", s.mux)
return nil
}
和结构
type Service struct {
Config // Hold db connection info
db *sql.DB
hc *health
}
我能够很好地测试各个部分(如initDB
或validate
),但我不清楚如何测试Run
函数因为http.ListenAndServe阻塞。我终于出去了。以前,我会使用httpTest并创建一个测试服务器,但那时main
将启动服务器(应用程序最初是更基本的)。
我要测试的一些东西:
我可以在启动时点击指标端点。一旦启动我就可以点击健康端点。我可以在队列上推送一条消息,一旦启动就收到它。 Run
实际上开始没有恐慌。
一些注意事项:我正在使用docker来启动队列和数据库。测试Run
函数的目的是确保引导有效并且应用程序可以成功运行。最终我想要通过队列推送数据并声明它已被正确处理。
问题:我应该如何测试或重构它以便它更容易端到端测试?
您可以使用goroutine构建测试工具,以在单元测试中执行Run
:
func TestRun(t *testing.T) {
service := Service{}
serviceRunning := make(chan struct{})
serviceDone := make(chan struct{})
go func() {
close(serviceRunning)
err := service.Run()
defer close(serviceDone)
}()
// wait until the goroutine started to run (1)
<-serviceRunning
//
// interact with your service to test whatever you want
//
// stop the service (2)
service.Shutdown()
// wait until the service is shutdown (3)
<-serviceDone
}
这只是一个基本的例子,说明如何在原则上完成它。有几点需要改进才能用于生产:
(0)最重要的细节:不要在生产中使用http.ListenAndServe
!改为创建自己的http.Server
实例。这为您省去了很多麻烦。
s.httpServer := http.Server {
Addr: ":8080",
Handler: s.mux,
}
(1)服务运行的指示应移入您的Service
类型。 Run
中的初始化部分可能需要一段时间,并且在调用ListenAndServe
之前应该关闭指示通道:
close(s.Running)
s.httpServer.ListenAndServe()
当然,您需要将指示通道添加到您的服务类型。
(2)将Shutdown
方法添加到称为Service
的s.httpServer.Shutdown()
。这将导致调用s.httpServer.ListenAndServe
返回错误http.ErrServerClosed
。
if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
return err
}
return nil
在测试结束时关闭服务非常重要。否则,您将无法为您的服务进行多次单元测试。无论如何,清理资源都是良好的公民身份。
(3)您需要等到service.Run
返回以确保服务实际关闭。
以上是关于如何测试/重构测试调用http.ListenAndServe的函数的主要内容,如果未能解决你的问题,请参考以下文章