英文:
Google cloud function Golang unit test with init()
问题
我在使用Golang创建Cloud Function并为其创建单元测试时遇到了问题。具体来说,在测试阶段我想要注入的环境变量没有被识别,因为init()函数总是在测试之前运行。而这个init()函数使用环境变量来创建一个客户端。有没有解决这个问题的方法?
Google建议将全局变量(如客户端)放在init()函数中,以便在将来的调用中重用这些对象。这样可以减少启动时间(来源)。
目录结构
/function
do_something.go
do_something_test.go
do_something.go
package main
import (
"context"
"log"
"os"
"cloud.google.com/go/firestore"
)
var (
projectID = os.Getenv("GCLOUD_PROJECT")
client *firestore.Client
)
func init() {
ctx := context.Background()
var err error
client, err = firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Firestore: %v", err)
}
}
func Main(w http.ResponseWriter, r *http.Request) {
// Do something
}
do_something_test.go
package main
import (
"os"
"testing"
)
func init() {
os.Setenv("GCLOUD_PROJECT", "my-test-project") // 这不起作用,因为按字典顺序,do_something.go中的init()在这个init()之前运行。
}
func TestMain(t *testing.T) {
os.Setenv("GCLOUD_PROJECT", "my-test-project") // 这不起作用,因为init()在TestMain之前运行。
}
可能的解决方案
-
不要在
do_something.go
中使用init()。然而,这会降低云函数的性能,由于启动时间延长,延迟也会增加。 -
通过配置文件注入变量。然而,我认为这会引入相同的问题。
-
在运行
go test
之前设置环境变量。这是可行的,但我认为这是一个次优的解决方案,因为我不想在实际测试之前运行额外的参数。 -
除非环境变量指定代码在生产环境中运行,否则始终默认为开发环境:
projectID = GetEnv("GCLOUD_PROJECT", "my-test-project")
func GetEnv(key string, defaultVal string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return defaultVal
}
英文:
I am having problems creating a Cloud Function in Golang and creating unit tests for it. Specifically, the environment variables that I want to inject during the test phase are not recognized, since the init() function always runs before the test. This init() function uses the environment variables to create a client. Is there any way around this problem?
Google recommends putting global variables like clients in the init() function, to reuse those objects in future invocations. This reduces startup time (source).
Directory structure
/function
do_something.go
do_something_test.go
do_something.go
package main
import (
"context"
"log"
"os"
"cloud.google.com/go/firestore"
)
var (
projectID = os.Getenv("GCLOUD_PROJECT")
client *firestore.Client
)
func init() {
ctx := context.Background()
var err error
client, err = firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Firestore: %v", err)
}
}
func Main(w http.ResponseWriter, r *http.Request) {
// Do something
}
do_something_test.go
package main
import (
"os"
"testing"
)
func init() {
os.Setenv("GCLOUD_PROJECT", "my-test-project") // This does not work because of lexigraphical order, init() in do_something.go before this init().
}
func TestMain(t *testing.T) {
os.Setenv("GCLOUD_PROJECT", "my-test-project") // This does not work because init() is run before TestMain.
}
Possible solutions
- Do not use init() in
do_something.go
. However, this gives a penalty in cloud function performance, latency is increased due to extended startup time. - Inject variables through a configuration file. However, I think this introduces the same problem.
- Set environment variables before running
go test
. This is feasible, however I find this a suboptimal solution, since I don't want to run extra arguments before doing the actual test. - Always default to the development environment unless an environment variable specifies the code runs in production:
projectID = GetEnv("GCLOUD_PROJECT", "my-test-project")
func GetEnv(key string, defaultVal string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return defaultVal
}
答案1
得分: 1
你应该在项目级别暴露一个环境变量,指明代码是在“测试”设置还是“生产”设置下执行。根据这个变量,你的init
函数将设置变量的值。
英文:
You should be exposing an environment variable at project level stating if the code is being executed in test
settings or prod
settings. Based on this, your init
function will set the values of the variables.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论