单元测试 – 先记录日志,然后失败?

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

Unit testing - log and then fail?

问题

我习惯于测试我的代码。现在我刚开始学习Go语言,希望尽快掌握。我正在使用标准库中的testing包,它似乎已经足够好了。(我也喜欢它不是另一个外部依赖项。与任何Java或Ruby项目相比,我们目前只有两个依赖项.....)无论如何,看起来在Go语言中,断言的写法如下:

func TestSomething(t *testing.T) {
  something := false
  if something {
    t.Log("Oh noes - something is false")
    t.Fail()      
  }
}

我觉得这样写有点啰嗦,我希望能够用一行代码实现,类似这样:

Assert(something, "Oh noes - something is false")

或者类似的方式。我希望我没有漏掉什么明显的东西。在Go语言中,最佳/惯用的做法是什么?

更新:只是为了澄清一下。如果我这样做:

func AssertTrue(t *testing.T, value bool, message string) {
  if value {
    t.Log(message)
    t.Fail()
  }
}

然后像这样编写我的测试:

func TestSomething(t *testing.T) {
  something := false
  AssertTrue(t, something, "Oh noes - something is false")
}

这样做就不符合Go语言的风格了吗?

英文:

I am used to test drive my code. Now that I am new to Go I am trying to get it right as fast as possible. I am using the testing package in the standard library which seem to be good enough. (I also like that it is not yet another external dependency. We are currently at 2 dependencies overall - compared to any Java- or Ruby project.....) Anyways - it looks like an assert in golang looks like this:

func TestSomething(t *testing.T) {
  something := false
  if something {
    t.Log("Oh noes - something is false")
    t.Fail()      
  }
}

I find this verbose and would like to do it on one line instead:

Assert( something, "Oh noes - something is false" )

or something like that. I hope that I have missed something obvious here. What is the best/idiomatic way to do it in go?

UPDATE: just to clarify. If I was to do something like this:

func AssertTrue(t *testing.T, value bool, message string) {
  if value {
    t.Log(message)
    t.Fail()
  }
}

and then write my test like this

func TestSomething(t *testing.T) {
  something := false
  AssertTrue(t, something, "Oh noes - something is false")
}

then it would not be the go way to do it?

答案1

得分: 17

有一些外部包可以与股票测试框架集成。

其中之一是我很久以前写的gocheck,旨在解决这种用例。

例如,测试用例如下所示:

func (s *Suite) TestFoo(c *gocheck.C) {
    // If this succeeds the world is doomed.
    c.Assert("line 1\nline 2", gocheck.Equals, "line 3")
}

您可以像往常一样使用go test运行它,该检查失败将报告为:

----------------------------------------------------------------------
FAIL: foo_test.go:34: Suite.TestFoo

all_test.go:34:
    // If this succeeds the world is doomed.
    c.Assert("line 1\nline 2", gocheck.Equals, "line 3")
... obtained string = "" +
...     "line 1\n" +
...     "line 2"
... expected string = "line 3"

请注意,代码上方的注释包含在报告的失败中。

还有许多其他常见功能,例如套件和测试特定的设置和拆卸程序等。请查看网页以获取更多详细信息。

由于我和其他人在许多活跃项目中使用它,因此它得到了很好的维护,所以请随时加入,或者跟进并查看适合您口味的其他类似项目。

有关gocheck使用的示例,请查看mgogoyamlgoamzpipevclockjuju(大型代码库)、lpadgozkgoetveldtomb等包。同时,gocheck也可以测试自身。这非常有趣。

英文:

There are external packages that can be integrated with the stock testing framework.

One of them I wrote long ago, gocheck, was intended to sort that kind of use case.

With it, the test case looks like this, for example:

func (s *Suite) TestFoo(c *gocheck.C) {
    // If this succeeds the world is doomed.
    c.Assert("line 1\nline 2", gocheck.Equals, "line 3")
}

You'd run that as usual, with go test, and the failure in that check would be reported as:

----------------------------------------------------------------------
FAIL: foo_test.go:34: Suite.TestFoo

all_test.go:34:
    // If this succeeds the world is doomed.
    c.Assert("line 1\nline 2", gocheck.Equals, "line 3")
... obtained string = "" +
...     "line 1\n" +
...     "line 2"
... expected string = "line 3"

Note how the comment right above the code was included in the reported failure.

There are also a number of other usual features, such as suite and test-specific set up and tear down routines, and so on. Please check out the web page for more details.

It's well maintained as I and other people use it in a number of active projects, so feel free to join on board, or follow up and check out the other similar projects that suit your taste more appropriately.

For examples of gocheck use, please have a look at packages such as mgo, goyaml, goamz, pipe, vclock, juju (massive code base), lpad, gozk, goetveld, tomb, etc. Also gocheck, manages to test itself. It was quite fun to bootstrap that.

答案2

得分: 1

但是当你像Uncle Martin一样编写测试时,测试中只有一个断言和很长的函数名,那么像http://github.com/stretchr/testify/assert这样的简单断言库可以使测试变得更快、更容易。

英文:

But when You try write test like Uncle Martin, with one assert in test and long function names, then simple assert library, like http://github.com/stretchr/testify/assert can make it much faster and easier

答案3

得分: 0

我不鼓励按照你所期望的方式编写测试。整个标准库之所以使用你所称之为“冗长”的方式,并非偶然。

这种方式确实需要更多的代码行数,但是有几个优点。

如果你阅读一下《为什么Go语言没有断言?》(http://golang.org/doc/faq#assertions)并将其中的“错误处理”替换为“测试失败报告”,你就能理解为什么Go语言的几个“断言”包不适合使用了。

再次强调,标准库的庞大代码基是证明。

英文:

I discourage writing test in the way you seem to have desire for. It's not by chance that the whole stdlib uses the, as you call it, "verbose" way.

It is undeniably more lines, but there are several advantages to this approach.

If you read Why does Go not have assertions? and s/error handling/test failure reporting/g you can get a picture of why the several "assert" packages for Go testing are not a good idea to use,

Once again, the proof is the huge code base of the stdlib.

答案4

得分: -1

习惯的方式就是你上面所示的方式。此外,如果你不想记录任何消息,也不必这样做。

根据Go的FAQ中的定义:

为什么Go没有断言?

Go不提供断言。它们无疑很方便,但我们的经验是,程序员使用它们作为避免考虑正确的错误处理和报告的依赖。正确的错误处理意味着服务器在非致命错误后继续运行,而不是崩溃。正确的错误报告意味着错误直接明了,使程序员不必解释一个庞大的崩溃跟踪。当看到错误的程序员对代码不熟悉时,准确的错误尤为重要。

我们理解这是一个有争议的问题。Go语言和库中有许多与现代实践不同的东西,仅仅是因为我们认为尝试不同的方法有时是值得的。

更新
根据你的更新,那不是Go的惯用方式。你所做的本质上是设计一个测试扩展框架,以模仿XUnit框架中的功能。虽然从工程角度来看,这没有什么根本性的问题,但它引发了关于维护这个扩展库的价值和成本的问题。此外,你正在创建一个内部标准,可能会引起争议。Go最重要的一点是它不是C、Java、C++或Python,应该按照语言的构造方式来完成事情。

英文:

The idiomatic way is the way you have above. Also, you don't have to log any message if you don't desire.

As defined by the GO FAQ:

Why does Go not have assertions?

> Go doesn't provide assertions. They are undeniably convenient, but our
> experience has been that programmers use them as a crutch to avoid
> thinking about proper error handling and reporting. Proper error
> handling means that servers continue operation after non-fatal errors
> instead of crashing. Proper error reporting means that errors are
> direct and to the point, saving the programmer from interpreting a
> large crash trace. Precise errors are particularly important when the
> programmer seeing the errors is not familiar with the code.
>
> We understand that this is a point of contention. There are many
> things in the Go language and libraries that differ from modern
> practices, simply because we feel it's sometimes worth trying a
> different approach.

UPDATE
Based on your update, that is not idiomatic Go. What you are doing is in essence designing a test extension framework to mirror what you get in the XUnit frameworks. While there is nothing fundamentally wrong, from an engineering perspective, it does raise questions as to the value + cost of maintaining this extension library. Additionally, you are creating an in-house standard that will potentially ruffle feathers. The biggest thing about Go is it is not C or Java or C++ or Python and things should be done the way the language is constructed.

huangapple
  • 本文由 发表于 2013年9月5日 21:38:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/18637912.html
匿名

发表评论

匿名网友

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

确定