Icon for gfsd IntelliJ IDEA

Writing better table-driven tests: pros and cons of different unit testing styles

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 an extension for GoLand and Visual Studio Code to help us write those unit tests. Let’s take a look!

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 standard Go style for writing table-driven tests has the fundamental flaw that it takes quite a bit of time and effort to figure out which test cases are failing, when one looks at the go test output and its stack traces. To resolve that problem, we developed our own unit testing style. 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, the 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 simply be can be skipped when using the Symflower table-driven style.
Named test cases Named test cases. By adding human-readable text, the next person looking at the test has a better experience and can get productive right away. 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. 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 comparing them with the Symflower style detailed above.

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 that a test case should check is 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 can make tests hard to follow
  • More fields and data can make these tests very hard to read and maintain

Symflower for VS Code and GoLand

Through better readability and the benefits outlined above, using the right style can streamline your unit testing efforts and improve your overall productivity. That saves some time, of course – but what if you did not have to spend time writing those unit tests in the first place? Here at Symflower, we’ve developed an extension for VS Code and GoLand that automatically generates meaningful unit tests for you, even letting you choose the style in which they should be written.

If you’re performing TDD, you’ll find our unit test templates helpful, as they greatly reduce the time you have to spend writing boilerplate code. However, the major productivity-enhancing feature of Symflower is that it can automatically create unit tests with meaningful values that are integrated in your existing test suite. Ready to run unit tests are just a click away – give Symflower a whirl to see how it works!

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 our unit test style.

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.

| 2022-02-21