Skip to content
This repository has been archived by the owner on Mar 11, 2021. It is now read-only.

Guideline or checklist on writing good (unit) tests #249

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

kwk
Copy link
Collaborator

@kwk kwk commented Sep 19, 2016

Hi,

while I was working on improving the coverage for some code parts, I discovered some nice things about testing in Go in particular. Those things may be fundamental to others but weren't for me when I started. Therefore, I created a document to write down my findings.

I'm going to update this document during the work I do now but I'd be happy for any comments or feedback if we want to have such a document in general.

It can be a living document for which we accept many PRs.

Unlike @sanbornsen 's email based on ALR's talk on testing, my document so far targets Go in particular. But we can incorporate the email here as well.

Regards.

@codecov-io
Copy link

codecov-io commented Sep 19, 2016

Current coverage is 20.13% (diff: 100%)

Merging #249 into master will not change coverage

@@             master       #249   diff @@
==========================================
  Files            32         32          
  Lines          1167       1167          
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
  Hits            235        235          
  Misses          888        888          
  Partials         44         44          

Powered by Codecov. Last update 893d58e...54d044e

@kwk kwk changed the title WIP Guideline or checklist on writing good (unit) tests Guideline or checklist on writing good (unit) tests Sep 19, 2016

=== Blackbox vs. Whitebox tests

In a blackbox test, you test a package as if you **only have access to the
Copy link
Contributor

@tsmaeder tsmaeder Sep 23, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really see what we gain by separating blackbox from whitebox testing. Anything that isn't reachable by public API is dead code anyway and does not have to be tested. Sometimes we can write test more easily by calling internal code, but in the end, it's all about coverage, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is about coverage and also about usage help I'd say. In principle somebody who would like to know how to use a package should take a look at the blackbox tests because this is the interface that one should be using. So separating the whitebox tests helps to bring some clarity for the reader.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you think of packages and their exported symbols as a contract, then the more whitebox tests we have the less strict is the contract of those packages.


In Go your test filenames must end with `_test.go`. In order to distinguish black-
and whitebox test files, a recommendation is to use the suffixes `_blackbox_test.go`
and `_whitebox_test.go`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes for long filenames. As @baijum (I think) suggested, we could have whitebox as the default and call blackbox tests "_bb_test.go". If we establish this as a pattern, people will know what it means.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd advocate to make the default a blackbox test because that is the test with the most value. Testing some internal functionality is also important of course. So I'd say package_test.go is the blackbox test and package_whitebox_test.go is the whitebox one. I don't care about the lengths of filenames at all and the naming pattern should be obvious. With whitebox_test the meaning is clear and except for it's length there's nothing to argue about. But wb_test could mean anything and requires explanation.

<6> Marking the test for the `Shout` function test as: "executable in parallel".

A few things to notice in <<lib-blackbox-test-dot-go-source>> is the package name: `bar_test`.
This is an exception to the Go compiler because normally only package names with the same name are
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not know that. To be honest: special casing this in the compiler to allow for cross-package tests seems like the wrong fix to me. But if this is the way it's meant to be, let's not try to swim against the stream.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testing.T..Parallel() Has nothing to do with optimizing the compiler.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about the _test package name, not t.Parallel()

total: (statements) 100.0%
----
<1> Runs all the tests in the `foo/bar` package and collects coverage information in the `cov.out` file.
<2> Prints coverage information per function in the package.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in chat, the coverage numbers for a package or function we generate from our makefile do not include coverage from test located in a different package. This will ignore coverage from end-to-end and cross-package integration tests.
As a group, we need to decide if that is a problem and needs to be fixed. There is a golang bug against this: golang/go#6909 Later comments include pointers to tools that work around this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A package should contain the tests it needs to be verified correct. And talking test coverage, it should be said that when you run go test -coverprofile=cov.out github.com/almighty/almighty-core/models you only want the models package to be tested and print a coverage for that. I'd say, that we should at least not be blocked by this and accept it the way it is right now.

The only reason why we still don't use the `-short` parameter is that we want to
have the ability to define more test-skipping criteria than just the time
consumed by a test.
That is why we have the `resource.require(t, resource.Database)` syntax to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful to explain the "require" concept a bit more and how to use it in tests. It's not entirely clear to me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure we can do that. Feel free to look at the code. It is easy to understand and I've added more documentation in my other PR: https://github.com/almighty/almighty-core/blob/629202a7431b665de15705f7e9f0688d15c4218b/resource/require.go

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add require to the test package where it should belong. But that can be done afterwards.

that have been marked to be executable in parallel. In this example, none of our tests
has any side effects and so they can be executed in parallel.
The number of parallel executable tests can be overwritten by the `-parallel` switch.

Copy link
Contributor

@ppitonak ppitonak Sep 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since tests on this level should be independent, can we switch to parallel execution by default, i.e. we would need to set serial execution explicitly in special cases.

Copy link

@hectorj2f hectorj2f left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kwk I don't know the state of this PR, although it LGTM. However I 'd say that the creation of blackbox tests can be optional, not required.

@kwk
Copy link
Collaborator Author

kwk commented Feb 21, 2017

@kwk I don't know the state of this PR, although it LGTM. However I 'd say that the creation of blackbox tests can be optional, not required.

Let's handle this in a while. I need to revise the PR.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants