17

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?

froderik
  • 4,642
  • 3
  • 33
  • 43
  • you test java code without any dependencies? Junit is not part of the JDK btw. – Woot4Moo Sep 05 '13 at 13:40
  • of course not. Compared to Java I like that there is a unit test framework in the standard library. There is one in Ruby also although people tend to use rspec anyway. Not sure about best practices in go... – froderik Sep 05 '13 at 13:42
  • I must have misread your original statement. – Woot4Moo Sep 05 '13 at 13:45
  • 2
    t.Log(); t.Fail() --> t.Errorf() which already saves you one line – Volker Sep 05 '13 at 13:58
  • I think I prefer them on two lines in the name of readability. I am more serious about readability than line numbers. – froderik Sep 05 '13 at 14:00
  • What is wrong with 3 lines? if something { t.Fail("Oh noes - something is false") } – alex Sep 05 '13 at 23:32
  • 4
    Calling AssertTrue(t, something, "Oh noes - something is false") is not good, because you loose source file name and line number info that Fail prints. – alex Sep 05 '13 at 23:35
  • good point - can't you get a stack out of the fail? – froderik Sep 06 '13 at 05:31
  • summed up my thoughts about this in a [post](http://highlevelbits.com/2013/09/pragmatic_unit_testing_with_go.html) – froderik Sep 08 '13 at 18:46

4 Answers4

17

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.

Gustavo Niemeyer
  • 22,007
  • 5
  • 57
  • 46
  • do you agree with the other answerers that using such a package is not the **go** way? – froderik Sep 05 '13 at 14:21
  • 1
    No, these are just personal preferences being loudly spoken. I've developed gocheck years ago, and multiple times over the unstable phase of the language implementation I talked to the core developers so they would keep the necessary features for gocheck to continue working. They don't use it, because they prefer something else, but they've never asked me to stop using it. – Gustavo Niemeyer Sep 05 '13 at 14:29
  • 1
    Also, some people think that with such a testing infrastructure you can't use "data oriented testing" (table-driven, etc). This is nonsense. You can use exactly the same techniques, and still get the convenience demonstrated above. – Gustavo Niemeyer Sep 05 '13 at 14:34
  • Ah, updated the example to demonstrate the logging of comments. – Gustavo Niemeyer Sep 05 '13 at 15:07
  • 1
    I've been using gocheck in my projects with success. The checkers are incredibly convenient compared to doing the checks manually, and the error messages are wonderful. My two nitpicks: - The boilerplate is a little annoying when I just want to write a single test function - The extra set of command line flags are confusing. Altogether I would definitely recommend using gocheck over nothing. – Rob Sep 06 '13 at 13:25
  • Yeah, we need a hook from testing to hide away the couple of lines that register gocheck into the usual test workflow. – Gustavo Niemeyer Sep 06 '13 at 14:16
  • As the question explicitly (and mainly) asks about “the go way” to test, maybe you could include your very insightful two comments to the beginning of this answer? If possible also how does the stdlib test. – Kissaki Sep 07 '13 at 13:28
1

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

BenMorel
  • 34,448
  • 50
  • 182
  • 322
DeyVpl
  • 21
  • 2
  • 3
    “But”?? What are you referring to? Who is uncle martin? What is faster - the coding or the execution? How is it easier? To write, read, understand? – Kissaki Sep 07 '13 at 13:21
0

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.

zzzz
  • 87,403
  • 16
  • 175
  • 139
  • @froderik: The Go Team which wrote the stdlib _does not_ use any assert/test libraries. Reason were already discussed. Some people consider the stdlib an informal style guide. Those people, like me as well, consider using assert/test libraries a bad style, IOW, not the Go way. – zzzz Sep 05 '13 at 14:27
  • 6
    I do not think that FAQ entry talks about the assert functionality the question is about. What the FAQ talks about are in-(production-)code assertions that verify something within program runtime. The question however is about using functions to assert test results. – Kissaki Sep 07 '13 at 13:20
  • 4
    I do not think that a good idea can be validated merely by usage number. Please name the “several advantages” you see, because I can not immediately see them. – Kissaki Sep 07 '13 at 13:24
  • @Kissaki: a) _"... and `s/error handling/test failure`"_ b) please read the link and do a). And: c) Use whatever you like. d) The Go Team doesn't like assertions. Not in code, nor in tests. Some people consider the stdlib a style guide. Some other people are funny enough to call such preferences a purism, worshiping or whatever other fictional term they must use to cope with a simple different opinion. For no good reason b/c, once again, no one is forcing anyone to use a particular style. Anyway I doubt a CL using test assertion helpers can get accepted in the Go tree. The conclusion is yours. – zzzz Sep 07 '13 at 18:09
  • I did go read the link, but it says nothing that seems relevant to tests. If a test fails on an assertion, then it isn't hard to understand, nor is it lazy error handling. It's precisely expressive and to the point, even for people not familiar with the code. Can someone who understands this situation comment on that? – Jonathan Hartley Feb 22 '18 at 18:13
-1

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.

Community
  • 1
  • 1
Woot4Moo
  • 23,987
  • 16
  • 94
  • 151
  • 8
    While I certainly agree that the standard library is an excellent reference for good code, and agree with many of the principles followed by the core team in terms of testing, it's not true that by simply integrating a helper package for testing you're departing from Go idioms. This is an unproductive level of purism and worshiping. – Gustavo Niemeyer Sep 05 '13 at 14:57
  • 1
    @GustavoNiemeyer while I appreciate your opinion, please remind me again who you are? – Woot4Moo Sep 05 '13 at 15:05
  • 6
    The FAQ entry you quote is about in-code assertions - verifications. The questions seems to be focused on testing though, so I do not think that FAQ entry is on topic here. Especially since the question names an assert function for his test assertions - quoting the FAQ entry may lead to confusion rather than clearing things up. – Kissaki Sep 07 '13 at 13:14
  • @Kissaki: Why do you ask him about why does he ask him to remind him who he is? Do you feel he is supposed to report to you his motivation? That said, I think you must know that the question was rhetorical (and to the point by its effects ;-), yet you're IMO purportedly ignoring that. – zzzz Sep 07 '13 at 18:15
  • Hmmm - I can see that my question may be thought of as rhetorical. That was not my intention. I am very new to go and need to find a good way to approach it. I will look out for the go way as I go along and see where that takes me. – froderik Sep 08 '13 at 18:32
  • @froderik: It was Woot4Moo's question above which I talked about ;-) – zzzz Sep 09 '13 at 07:46
  • 1
    The quoted section of the FAQ provides lots of very good points about production code, but none of them are in any way relevant for using assertions in tests. When a test fails on an assertion, or an assert-like function call, this is in no way a "lazy thinking about error handling". Nor is it difficult to understand - to the contrary it is precisely expressive of the intent of the test, even for people unfamiliar with the code. – Jonathan Hartley Feb 22 '18 at 18:17