Go单元测试无关的错误“主机名解析错误”

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

Go Unit Test irrelevant error "hostname resolving error"

问题

我正在尝试为这个项目编写单元测试。看起来我需要进行大量的重构,并且目前正在进行中。为了测试project/api/handlers.go中的函数,我尝试编写一些单元测试代码,但总是遇到与数据库初始化相关的错误。数据库来自于Psql Docker容器。错误显示给定的主机名无效,但是在没有进行测试的情况下,它可以正常工作。此外,对于Docker化的PostgreSQL,容器名称被用作主机名,这不应该是一个问题。

错误信息如下:

DB连接错误:无法连接到host=postgresdbT user=postgres database=worth2watchdb:主机名解析错误(查找postgresdbT:没有这样的主机)
进程以退出代码1结束

无论如何,我进行了一些重构,并成功将函数从DB查询函数中抽象出来,但是这个错误仍然发生,我无法进行测试。所以最后我决定在同一个包中执行一个完全空白的测试,只是简单地使用bcrypt包进行检查。

func TestCheckPasswordHash(t *testing.T) {
    ret, err := HashPassword("password")
    assert.Nil(t, err)
    ok := CheckPasswordHash("password", ret)
    if !ok {
        t.Fail()
    }
}

//HashPassword函数使用bcrypt算法对密码进行哈希处理,并使用Cost值返回哈希字符串和错误
func HashPassword(password string) (string, error) {
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), 4)
    return string(bytes), err
}

//CheckPasswordHash函数检查两个输入,并在匹配时返回TRUE
func CheckPasswordHash(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

然而,当我尝试仅对TestCheckPasswordHash函数执行测试时,使用命令go test -run TestCheckPasswordHash ./api,仍然出现相同的错误。顺便说一下,文件名是handlers_test.go,函数位于handlers.go文件中,包名对于两者都是api。

虽然没有与任何类型的数据库相关的函数联系,但我一次又一次地遇到相同的错误。当我在另一个项目中运行这个TestCheckPasswordHash代码,或者在project/util/util_test.go中运行它时,它会按预期进行检查并通过。

我不知道该怎么办,除非解决这个问题,否则似乎无法在这个包中执行任何测试。

提前感谢。祝一切顺利。

英文:

I am trying to write unit test for this project

It appears that i need to refactor a lot and currently working on it. In order to test functions in project/api/handlers.go i was trying to write some unit test code however always taking error related with DB initializing. DB is from Psql Docker container. Error says given hostname is not valid, however without testing it works as no problem. Also, for Dockerized postgresql, container name is being used as hostname and this shouldn't be a problem.

The error is:

> DB connection error: failed to connect to host=postgresdbT user=postgres database=worth2watchdb: hostname resolving error (lookup postgresdbT: no such host)
Process finished with the exit code 1

Anyway, i did a couple refactor and managed abstracting functions from DB query functions however this error still occurs and i cannot perform the test. So finally i decided to perform a totally blank test within same package simply checks with bcrypt package.

func TestCheckPasswordHash(t *testing.T) {
ret, err := HashPassword("password")
assert.Nil(t, err)
ok := CheckPasswordHash("password", ret)
if !ok {
	t.Fail()
}
}


//HashPassword function hashes password with bcrypt algorithm as Cost value and return hashed string value with an error
func HashPassword(password string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), 4)
	return string(bytes), err
}

//CheckPasswordHash function checks two inputs and returns TRUE if matches
func CheckPasswordHash(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

However when I've tried to perform test for only TestCheckPasswordHash function with command of go test -run TestCheckPasswordHash ./api, it still gives same error. Btw, File is handlers_test.go, functions are at handlers.go file, package name is api for both .

There is no contact with any kind of DB related functions however i am having same error again and again. When i run this TestCheckPasswordHash code in another project or at project/util/util_test.go, it checks and passes as expected.

I don't know what to do, it seems that i cannot perform any test in this package unless figure this out.

Thanks in advance. Best wishes.

答案1

得分: 1

检查了你的代码库,实现得很好,整洁简单,做得很好!

我认为问题出在init函数中,请尝试将其注释掉,看看是否可以解决单个测试的问题。

很难在没有文件图形示例的情况下解释init函数的工作原理,但你可以查看官方文档:
https://go.dev/doc/effective_go#init

附注:如果这不起作用,请给我回信。

英文:

Was checking your repo, nice implementation, neat an simple good job!

I think your issue is in the init function, please try commenting it out and see if it work for that single test.

Is a bit complex to explain how the init function works without a graph of files as example but you can check the official documentation:
https://go.dev/doc/effective_go#init

PD: if this doesn't work please write me back

答案2

得分: 0

我找到了导致这个错误的原因,现在已经解决了。

这部分与Docker的工作原理有关,DB_Hostname必须声明,但我们对此无能为力。所以我们需要一个更好的方法来解决。

当执行go test命令时,Go测试逻辑按照执行顺序检查整个包(而不是整个项目),例如首先是变量声明和init()函数。在调用外部包项时,运行时也会绕过该包。

即使你只测试一个无关的函数,在执行测试之前,Go运行时也会评估整个包。

为了防止这种情况发生,我将包级别的变量(即使它们在另一个包中)封装起来,直接调用DB和缓存。在初始阶段,这些变量可以分配为新变量。然而,它们的连接将由main或main.init()确保。

现在,在进行测试之前,检查所有相关的变量(在同一个包中或通过外部)。假设如果需要DB代理(redis.client或pgxpool.Pool),我们将创建一个新的代理,编译器不会报错,然后开始测试。代理只能通过从main或其他我们想要的地方调用函数来运行。

这是一种更可维护的代码实践(可能不是最佳实践)。依赖项的初始化应该能够谨慎处理,并与功能需求相关。至少,通过简单的重构,问题应该可以解决。

英文:

I've found the reason why this error occured and now it's solved.

This is partially related with Docker's working principle of how DB_Hostname must be declared but we can do nothing about it. So we need a better approach to overcome.

When go test command executed for (even) a function, Go testing logic checks whole package(not whole project) as per execution order, such as firstly variable declarations and init() function later. In case of calling an external package item, runtime detours that package for the item also.

Even if you are testing only an irrelevant function, you should consider that, before performing the test, Go runtime will evaluate whole package.

In order to prevent this, i wrapped the package level variables(even though they are in another package) that directly calls DB and cache. On initial stage, these can be allocated as a new variable. However, their connection will be ensured by main or main.init()

And now, prior to testing, all relevant variables (in same package or via external) are checked. Let's say if DB agent (redis.client or pgxpool.Pool) is needed, we are creating a new agent, compiler doesn't complain and testing begins. Agent will be operational only by a function call from main or somewhere we want to.

This is a better(may be not best) practice for a more maintainable code. Initialization of dependants should be able to be handled cautiously and in context with the functional needs. At least, with a simple refactoring, problem should be solvable.

huangapple
  • 本文由 发表于 2022年5月12日 02:29:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/72205972.html
匿名

发表评论

匿名网友

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

确定