去单元测试的致命错误和测试main() [英] Go Unit-Testing fatals and testing main()

查看:213
本文介绍了去单元测试的致命错误和测试main()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我非常新到使用PHPUnit测试从PHP背景进行测试。在PHP中,非常相似地鼓吹你需要100%的覆盖率。
在Go中,大多数我读过的关于测试的东西似乎很少,没有像引发错误的东西。



例如我的小程序:

  func main(){
config = readConfig(config.json)
}

func readConfig(路径字符串)Config {
var cfg配置
文件,err:= ioutil.ReadFile(路径)
如果err!= nil {
log.Fatal(err )
}
err = json.Unmarshal(file,& cfg)
if err!= nil {
log.Fatal(err)
}
返回cfg


func TestCanReadConfig(t * testing.T){
cfg:= readConfig(test_data / config.json)
if cfg。 Broker_pass!=test|| cfg.Broker_port!=3333{
t.Error(invalid config)
}
}

现在在我的例子中,我会遇到覆盖问题,因为main()在单元测试中根本没有被覆盖(它应该如何?)



2 log.Fatal()完全没有被覆盖。



我的问题是,我该如何精确地编写我的测试?我是否以不太严格的风格进行测试,而不是测试每种可能的场景,或者我可以使用
@expectedException \InvalidArgumentException
来进行注释我还是应该测试主要功能?如果不是,我可以以某种方式忽略覆盖工具吗?我应该考虑一个测试框架吗?
大多数测试教程都很好,但非常简短,只介绍简单的测试。

解决方案

这取决于你的喜好,但是:

a。不要测试 main 。 main只应该调用经过测试的代码,最好在其他包中。尽可能多地为这些软件包提供代码覆盖范围,并尽可能地让主程序变得微不足道。不管覆盖面如何,这是一个很好的做法。所以这不是一个真正的问题。

b。不要使用 log.Fatal 作为可测试代码,只返回错误。您可以在应用程序初始化代码中保留 log.Fatal ,即 - main :)。因此,如果主调用 readConfig 并且失败,它只会返回一个错误(非常可测!)。添加的应用程序行为 log.Fatal 是main的工作 - 配置读者不应该像决定是否应该退出应用程序那样处理事情,对吧?它只是读取配置并告诉你它是否成功。应用程序决定如何处理它。



因此,您的代码可能如下所示:

  func readConfig(path string)(Config,error){
var cfg配置
文件,err:= ioutil.ReadFile(路径)
如果err!= nil {
return cfg,err
}
err = json.Unmarshal(file& cfg)
if err!= nil {
return cfg,err
}
return cfg,nil
}

func main(){
config,err:= readConfig(config.json)
if err != nil {
log.Fatal(err)
}

}

现在,您已将逻辑从应用程序行为中分离出来,并且 readConfig 完全可以测试。

I'm pretty new to go testing coming from a background of PHP with PHPUnit tests.

In PHP it's pretty much reliously preached that you need 100% coverage. In Go most stuff i've read about tests seem to minimal, without stuff like provoking errors.

For example my small program:

func main() {
    config = readConfig("config.json")
}

func readConfig(path string) Config {
    var cfg Config
    file, err := ioutil.ReadFile(path)
    if err != nil {
        log.Fatal(err)
    }
    err = json.Unmarshal(file, &cfg)
    if err != nil {
        log.Fatal(err)
    }
    return cfg
}

func TestCanReadConfig(t *testing.T) {
    cfg := readConfig("test_data/config.json")
    if cfg.Broker_pass != "test" || cfg.Broker_port != "3333" {
        t.Error("invalid config")
    }
}

now in my example I would have issues with coverage because main() isn't covered at all in Unit tests (How should it?)

And the 2 log.Fatal()'s are not covered at all.

My question is how do I write my tests exactly in go? Do I do it in a less strict style not testing every possible scenario or can I do annotation like in php with @expectedException \InvalidArgumentException Can I or should I test the main function? If not can I ignore it from the coverage tool somehow? Should I consider a testing framework? Most testing tutorial are nice but very short and only introducing simple tests.

解决方案

it's not a Go thing per-se, it depends on your preference, but:

a. don't test main. main should only invoke tested code, preferably in other packages. Provide as much code coverage as you can to those packages, and leave main as trivial as possibly. That's a good practice regardless of coverage. So that's not really a problem.

b. Don't use log.Fatal for testable code, just return errors. You can keep log.Fatal in application init code, i.e. - in main :). So if main calls readConfig and it fails, it just returns an error (very testable!). The added application behavior of log.Fatal is main's job - the configuration reader shouldn't handle things like deciding if we should quit the application, right? It just reads configurations and tells you if it succeeded. The application decides what to do with it.

So your code might look like:

func readConfig(path string) (Config, error) {
    var cfg Config
    file, err := ioutil.ReadFile(path)
    if err != nil {
        return cfg, err
    }
    err = json.Unmarshal(file, &cfg)
    if err != nil {
        return cfg, err
    }
    return cfg, nil
}

func main() {
    config, err := readConfig("config.json")
    if err != nil {
        log.Fatal(err)
    }

}

And now you've separated logic from application behavior, and readConfig is perfectly testable.

这篇关于去单元测试的致命错误和测试main()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆