Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 11 Next »

The Liquibase code contains both unit tests and integration tests. This document explains the basics of creating Unit tests that will be used by the automated build process to validate Liquibase and reduce regressions.

Unit Tests

Unit tests test functionality in isolation, without any external systeminteraction. Because there are no external dependencies, these tests need no additional setup and run fast.

Liquibase Unit tests are written using the Spock testing framework.

Naming and Location of the Unit Test

Unit tests are written at the Java class level. There is a 1-1 mapping between the unit test class and the Java class being tested. The unit test class has the same package and name as the Java class, but with Test.groovy appended. All test classes are stored using the src/test/groovy structure expected by Maven.

Here is the example for liquibase-core/src/main/java/liquibase/util/StringUtil.java

  1. Replace main/java in the file path with the new substring src/test/groovy

    • liquibase-core/src/main/java/liquibase/util/

    • liquibase-core/src/src/test/groovy/liquibase/util/

  2. If a unit test doesn’t already exist, create a new unit test class with the same base filename as the Java class and append Test.groovy

    1. liquibase-core/src/main/java/liquibase/util/StringUtilTest.groovy

  3. The next step is to create the actual test

Creating the Unit Test

In this example, we added a new method in this class named public static String StringUtil.trimToNull(String). The goal of the method is to return a new string with leading and training whitespace removed. If the resulting string is empty, then return null.

The Java Class to Test

See the actual Java class in GitHub -https://github.com/liquibase/liquibase/blob/master/liquibase-core/src/main/java/liquibase/util/StringUtil.java- or the edited example below:

liquibase-core/src/main/java/liquibase/util/StringUtil.java

package liquibase.util;

import liquibase.ExtensibleObject;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;

/**
 * Various utility methods for working with strings.
 */
public class StringUtil {
    private static final Pattern upperCasePattern = Pattern.compile(".*[A-Z].*");
    private static final Pattern lowerCasePattern = Pattern.compile(".*[a-z].*");
    private static final SecureRandom rnd = new SecureRandom();
    /**
     * Returns the trimmed (left and right) form of the input string. If the string is empty after trimming (or null
     * was passed in the first place), null is returned, i.e. the input string is reduced to nothing.
     * @param string the string to trim
     * @return the trimmed string or null
     */
... 
    public static String trimToNull(String string) {
        if (string == null) {
            return null;
        }
        String returnString = string.trim();
        if (returnString.isEmpty()) {
            return null;
        } else {
            return returnString;
        }
    }
...
}

The Unit Test

See the actual Unit Test class in GitHub -https://github.com/liquibase/liquibase/blob/master/liquibase-core/src/test/groovy/liquibase/util/StringUtilTest.groovy- or the edited example below:

1. In the liquibase-core/src/src/test/groovy/liquibase/util/ directory, create or edit the StringUtilTest.groovy file. Add the following new test method to test the trimToNull() method in the Java class.

The test method name should descriptive of what is being tested. At a minimum it should be the name of the method under test, but ideally it should describe what is being tested by the method.

class StringUtilTest extends Specification {
...
    def "trimToNull"() {
        
    }
...    
}

2. Add a simple assertion. In this case, there is no setup needed so a simple “expect” works best. If you are new to the Spock testing framework and need more information on the syntax below, please read Spock Test Framework - Getting Started.

Focus on test readability. What is being tested and why should be immediately obvious to anyone looking at the test.

    def "trimToNull"() {
        expect:
        StringUtil.trimToNull("test string") == "test string"
    }

3. Refactor and expand your test with more test cases. Try to think of test for all the edge cases. Specify the test variations in the where clause.

Use more “where” data over additional tests. Before adding a new test method, look at the existing tests and see if any can be refactored to include your scenario.

@Unroll("#featureName: '#input'")
def "trimToNull"() {
    expect:
    StringUtil.trimToNull(input) == expected

    where:
    input                     | expected
    "test string"             | "test string"
    "test string   "          | "test string"
    "   test string"          | "test string"
    "   test string     "     | "test string"
    "test    string"          | "test    string"
    ""                        | null
    "    "                    | null
    "\n\r\ttest string\r\n\t" | "test string"
}

Running and Testing the Unit Test

The Spock framework is an extension of JUnit. During development it is normally executed through your IDE just like any other test. Your IDE will let you choose which test (or all the tests) you want to run.

You are also able to run all unit tests via the maven command - mvn test.

<provide step by step on running the command via maven - please also include output>

  • No labels