在Go语言中重新定义常量(const)进行测试。

huangapple go评论82阅读模式
英文:

Redefine const in golang for test

问题

我正在为一个服务编写一个HTTP客户端,并且为了测试,我想使用net/http/httptest服务器而不是调用远程API。如果我将baseUrl设置为全局变量,它可以很容易地指向我的测试服务器的URL。然而,这样做会使生产代码更加脆弱,因为baseUrl在运行时也可以被更改。我的首选是将baseUrl作为生产代码的const,但仍然能够更改它。

package main

const baseUrl = "http://google.com"

// 在 main_test.go 中
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  ...
}))
const baseUrl = ts.URL
// 上面的代码会报错:const baseUrl already defined
英文:

I'm writing an http client for a service and for testing I want to use a net/http/httptest server instead of calling out to the remote API. I can easily do this if I make the baseUrl a global variable which gets set to the url of my test server. However, this makes the production code more fragile because baseUrl can also be changed during runtime. My preference would be to make baseUrl a const for production code but still be able to change.

package main
const baseUrl = "http://google.com"

// in main_test.go
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  ...
 }
const baseUrl = ts.URL
// above line throws const baseUrl already defined error

答案1

得分: 17

如果你的代码使用了一个常量值,那么它就不够“测试友好”(指的是在测试时使用不同的参数值进行测试)。

你可以通过稍微重构的方式来解决这个问题。假设你有一个使用这个常量的函数:

const baseUrl = "http://google.com"

func MyFunc() string {
    // 使用 baseUrl
}

你可以创建另一个函数,将基本URL作为参数传入,然后你的原始 MyFunc() 调用这个函数:

const baseUrl_ = "http://google.com"

func MyFunc() string {
    // 调用另一个函数并传入常量值
    return myFuncImpl(baseUrl_)
}

func myFuncImpl(baseUrl string) string {
    // 使用 baseUrl
    // 这里是原始 MyFunc() 函数中的相同实现
}

这样,你的库的API不会改变,但现在你可以通过测试 myFuncImpl() 来测试原始 MyFunc() 的功能,并且你可以传入任何值进行测试。

调用 MyFunc() 仍然是安全的,因为它总是将常量 baseUrl_ 传递给 myFuncImpl(),而现在实现代码位于 myFuncImpl() 中。你可以决定是否将这个新的 myFuncImpl() 函数导出,它可以保持未导出状态,因为测试代码可以(应该)放在同一个包中,并且可以无问题地调用它。

英文:

If your code uses a const value, it is not testing-friendly (regarding testing with different values of that parameter).

You could approach your problem with a slight refactoring. Let's say you have a function that uses this const:

const baseUrl = "http://google.com"

func MyFunc() string {
    // use baseUrl
}

You could create another function that takes base URL as a parameter, and your original MyFunc() calls this:

const baseUrl_ = "http://google.com"

func MyFunc() string {
    // Call other function passing the const value
    return myFuncImpl(baseUrl_)
}

func myFuncImpl(baseUrl string) string {
    // use baseUrl
    // Same implementation that was in your original MyFunc() function
}

This way the API of your library doesn't change, but now you can test the functionality of your original MyFunc() by testing myFuncImpl(), and you can pass any value to test with.

Calling MyFunc() will remain safe as it always passes the const baseUrl_ to myFuncImpl() where the implementation now resides. It's your decision whether you make this new myFuncImpl() function exported or not; it may remain unexported as testing code may (should) be placed in the same package and can call it without problems.

huangapple
  • 本文由 发表于 2015年11月18日 15:51:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/33774420.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定