Better table-driven tests: generating Symflower-style unit tests

Generate unit tests with the Symflower Visual Studio Code extension

Ever wondered what the best style for writing unit tests is? We at Symflower have a certain take on that. We developed a test style optimized towards debuggability, readability and understandability. This reduces the time spent on finding failing tests and understanding test cases, and therefore allows us to spend more time on actual development. We also created a Visual Studio Code extension to help us write those unit tests. Let’s take a look at both of them!

Table of contents

Symflower-style table-driven unit tests

In the beginning of Symflower, we were using the standard Go style for writing our table-driven tests. Over time we got increasingly unhappy with that style. The main reason was that it took some time and effort to figure out which test case was failing when we looked at the go test output and its stack traces. We, therefore, developed our own style which solves this problem. By encapsulating the test cases in a call to a validation function, we were able to get meaningful stack traces for failing tests while still sticking to a table-driven style.

Symflower-style table-driven unit test

Characteristics

  • Table-driven
  • Validation function
  • Named test cases
  • Structured test cases

Benefits

  • Meaningful stack traces for failing tests
  • Improved readability and understandability by named and structured test cases
  • Reuse of validation code

The main purpose of our style is an improvement in debuggability and readability. Both aspects help us spend less time on debugging tests and stay focused on actual coding.

Stack traces for failing tests Stack traces for failing tests. This is probably the most important benefit of this style. Because of the calls to the validation function, each stack trace holds a location to the failing test case. In comparison, standard Go table-driven style can only have stack traces pointing to the validation, since the test cases do not forward their source code location. Developers often work around this problem by adding the name of the test cases to the assert messages, which can be can be skipped with the Symflower table-driven style as well.
Named test cases Named test cases. By adding human-readable text, the experience for the next person who is looking at the tests is improved. The named test cases also describe the behavior the test is supposed to check. This introduces a flavor of behavior-driven development to our unit tests. Another aspect of named tests is that they are easier to find if you are looking for a specific one.
Structured test cases Structured test cases. The test case definitions are split into name, input, and output by adding blank lines in between them. This way, it’s always clear what the input and the expected output is. We do this regardless of whether there are multiple arguments or just a single one, it’s a convention. Another important point is that we always make use of the field names in struct literals. Otherwise, it would become unreadable when several fields are involved.

Other test styles

There are, of course, other frequently used test styles out there. We’ll briefly showcase them for you, so that you have a proper base for comparison with the Symflower style.

Function per test case

This is the most basic test style. Since every test case gets its own test function, there is a lot of redundant code, and the specific behavior a test case should check is also not described.

Function per test case style for table-driven unit test

Disadvantages

  • Redundant validation code
  • Overview of existing tests is not great
  • Long and hard to read test function names

Standard Go style

This is the style you see most often in Go projects. It’s already table-driven, which is a huge improvement to the function-per-test-case style, since it reduces the amount of redundant code. However, there are still disadvantages, which are overcome by our style.

Standard Go style for table-driven unit test

Disadvantages

  • No relevant stack traces for failing tests
  • No description of the behavior the test cases should check
  • Missing field names make tests often hard to follow
  • More fields and data make these tests often very hard to read and maintain

The Symflower VS Code Extension

Creating unit tests will always involve writing some boiler-plate code. That’s where editor extensions come in handy. The Symflower Visual Studio Code extension allows you to generate tests in the above unit test style, and even maintain them. Please drop us a line on our public issue tracker if you are missing a feature, found a bug or just want to tell us how you like the extension and the unit test style.

The Symflower Visual Studio Code Extension

Our main area of expertise at Symflower is, however, generating actual unit tests, and not just test skeletons. With this in mind, the next feature in our pipeline is going to be aimed at providing you with unit tests that are integrated in your existing test suite. Sign up for our newsletter and follow us on Twitter, Facebook, and LinkedIn to get notified about the upcoming releases and news about programming and tech.

Technical | 2022-02-21