I always thought that good unit test, are test that are independent. By 'independent' i mean that when function 'A' uses 'B', and we test function 'A', we mock/stub out 'B' in case when 'B' does not work correctly it will not fail 'A'.
But when we check sources of golang packages that principle is not respected.
For example lets check url.go and url_test.go in url packages:
url.go:
func parseQuery(m Values, query string) (err error) {
for query != "" {
...
key, err1 := QueryUnescape(key)
...
url_test.go:
func TestParseQuery(t *testing.T) {
for i, test := range parseTests {
form, err := ParseQuery(test.query)
...
As we can see parseQuery
use QueryUnescape
. In test QueryUnescape
is not stubbed in any way. So if QueryUnescape
will work wrong, parseQuery
test will fail.
So authors of package not always meet requirement of 'independent' unit test. What was the reason to not bother about this principle in this case, is there some rule that allow programmer of accepting this form of unit tests?
After writing independent test in python, I'am little confused about balancing between writing perfect test(which much affects in golang about design of code) and results.
A good unit test tells a story about some behavioral aspect of our application, so it should be easy to understand which scenario is being tested and — if the test fails — easy to detect how to address the problem. With a good unit test, we can fix a bug without actually debugging the code!
Aim for 95% or higher coverage with unit tests for new application code. When developers unit test as they program, they improve the longevity and quality of the codebase. The time a development team invests in unit tests pays off with less time spent troubleshooting defects and analyzing problems later.
At the command line in the greetings directory, run the go test command to execute the test. The go test command executes test functions (whose names begin with Test ) in test files (whose names end with _test.go). You can add the -v flag to get verbose output that lists all of the tests and their results.
Your question is really about defining the scope of a "unit" when "unit testing", which can be tricky. A "unit" does not necessarily mean a function, or a struct. It might mean a few functions/structs working together. But it most certainly means that you will not cross process boundaries (like using the real file system or going over a network, hitting a database, etc...). The boundaries are tested with integration tests or simulated using test doubles (mocks, stubs, spies, etc...).
I'm the author of GoConvey, a testing tool that build on top of the built-in go "testing" package. GoConvey has a comprehensive suite of unit tests. In the tests for the core of the project I don't write tests that invoke every single exported and non-exported function. I wrote the tests with the public-facing API in mind (the exported functions/structs). The implementation of that API is not the concern of my unit tests but the outcome is. You can see what I mean just by reading a few tests. I only call a few public-facing methods and assert that the result is correct. There are actually lots of structs and functions being invoked but the test coverage in that package is very high (currently 92.8%--not as high as I'd like but it's pretty good).
In the case of the convey
package within GoConvey the unit is the entire package and its components. In the beginning I remember the tests being more granular, which allowed me to get into the red-green-refactor cycle more quickly. As the code grew, those smaller-scoped tests were superseded by broader tests that seemed more appropriate. So the suite will evolve with the production code. You'll feel a lot of friction and inertia if every single method is tested directly as you won't be able to change anything without breaking a bunch of tests.
Here's another interesting summary about how to discern the scope of a unit test:
http://blog.8thlight.com/uncle-bob/2014/01/27/TheChickenOrTheRoad.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With