BLOG

Table of Contents
    Enhancing Unit Testing in Golang: Testify and More
    Make writing unit test easy again!

    In my work, I often need to write a large number of unit tests. Generally speaking, tests should cover as much code and various scenarios as possible. They should also ensure consistency, independence, singularity, and stability. A set of excellent tests can help engineers more easily discover potential problems before going live and ensure system stability when facing destructive changes.

    The most popular testing framework in Golang is Testify, which supports the basic functions of modern testing frameworks, including:

    • Assertions
    • Mocking
    • Testing suite interfaces and functions

    For company projects, Testify has met all the testing scenarios, and the projects have always maintained stable operation. As a testing framework, Testify's versatility and coupling degree have always been well maintained. However, for specific projects, there is still many aspects for optimization. For example:

    • Using the transaction function of the database to automatically delete test data after the test ends.
    • Extensively using factory functions in the testing framework to initialize the functions under test, test data, and user permissions (previous projects still used raw SQL queries to initialize data).
    • Using generics and serialization to reduce the writing of test code, and storing test data and expected results in separate test files.

    Most databases do not support nested transactions. They use savepoints instead. So during testing, you need to check whether the current query is in a transaction.
    It's good to store the transaction status in a context or create a wrapper.

    By greatly improving the reusability of functions and separating the implementation of tests from data, the person writing the tests can temporarily ignore the dependency relationship between functions and data and focus on writing core test cases.

    Although this version of the code solves many engineering problems, it is not advanced enough. For example, after introducing the factory pattern, it is actually possible to use large language models (LLMs) for batch generation of test data. If data training can be performed based on test data and coverage, I dare not imagine how happy I will be in the future (letting my imagination run wild).