The Ballerina Test framework has configurations at various levels to streamline the testing process and ensure that the tests are written with a comprehensible structure.
Set up and tear down
The following test annotations can be used to set up and tear down the instructions. These configuration annotations enable executing instructions at various levels.
Suite level
The @test:BeforeSuite
annotation
The function annotated with the BeforeSuite
annotation will be run once before any of the tests in the test suite. This can be used for initializing the test suite level prerequisites.
Example:
import ballerina/io; import ballerina/test; // The `BeforeSuite` function is executed before running all the test // functions in this module. @test:BeforeSuite function beforeFunc() { io:println("I'm the before suite function!"); } // Test function. @test:Config function testFunction1() { io:println("I'm in test function 1!"); test:assertTrue(true, msg = "Failed"); } // Test function. @test:Config function testFunction2() { io:println("I'm in test function 2!"); test:assertTrue(true, msg = "Failed"); }
The @test:AfterSuite
annotation
The AfterSuite
annotated function will be run once after all the tests in the test suite are run. This can be used for cleaning up at the test suite level. A test suite covers tests related to a module.
Example:
import ballerina/io; import ballerina/test; // Test function. @test:Config function testFunction1() { io:println("I'm in test function 1!"); test:assertTrue(true, msg = "Failed"); } // The `AfterSuite` function is executed after all the test functions in this module. @test:AfterSuite function afterFunc() { io:println("I'm the after suite function!"); }
Group level
The @test:BeforeGroups
annotation
For each group specified in this annotation, the BeforeGroups
annotated function will be executed once before any of the tests belonging to the group.
Example:
import ballerina/io; import ballerina/test; // The `beforeGroups1` function is executed before running all the test functions // belonging to the `g1` group. @test:BeforeGroups {value: ["g1"]} function beforeGroups1() { io:println("I'm the before groups function!"); } // Another `beforeGroups2` function is executed before running all the test functions // belonging to the `g1` and `g2` groups. @test:BeforeGroups {value: ["g1", "g2"]} function beforeGroups2() { io:println("I'm another before groups function!"); } // A test function that belongs to the `g1` group. @test:Config {groups: ["g1"]} function testFunction1() { io:println("I belong to group g1!"); test:assertTrue(true, msg = "Failed"); } // A test function that belongs to the `g2` group. @test:Config {groups: ["g2"]} function testFunction2() { io:println("I belong to group g2 "); test:assertTrue(true, msg = "Failed"); }
The @test:AfterGroups
annotation
For each group specified in this annotation, the AfterGroups
annotated function will be executed once after all the tests belonging to the group is executed.
Example:
import ballerina/io; import ballerina/test; // A test function that belongs to the `g1` group. @test:Config {groups: ["g1"]} function testFunction1() { io:println("I belong to group g1!"); test:assertTrue(true, msg = "Failed"); } // A test function that belongs to the `g2` group. @test:Config {groups: ["g2"]} function testFunction2() { io:println("I belong to group g2 "); test:assertTrue(true, msg = "Failed"); } // The `afterGroupsFunc1` function is executed before running all the test functions // belonging to the `g1` group. @test:AfterGroups {value: ["g1"]} function afterGroupsFunc1() { io:println("I'm the after groups function!"); } // The `afterGroupsFunc2` function is executed before running all the test functions // belonging to the `g1` and `g2` groups. @test:AfterGroups {value: ["g1", "g2"]} function afterGroupsFunc2() { io:println("I'm another after groups function!"); }
Test case level
The @test:BeforeEach
annotation
The BeforeEach
annotated function will be run before each test in the test suite. This can be used to initialize the test-level prerequisites repeatedly before every test function.
Example:
import ballerina/io; import ballerina/test; // The `BeforeEach` function, which is executed before each test function. @test:BeforeEach function beforeFunc() { io:println("I'm the before function!"); } // The first test function. @test:Config function testFunction1() { io:println("I'm in test function 1!"); test:assertTrue(true, msg = "Failed!"); } // The second test function. @test:Config function testFunction2() { io:println("I'm in test function 2!"); test:assertTrue(true, msg = "Failed!"); } // The third test function. @test:Config function testFunction3() { io:println("I'm in test function 3!"); test:assertTrue(true, msg = "Failed!"); }
The @test:AfterEach
annotation
The AfterEach
annotated function will be run after each test within the test suite. This can be used to clean up the test-level aspects repeatedly after every test function.
Example:
import ballerina/io; import ballerina/test; // This `AfterEach` function is executed before each test function. @test:AfterEach function afterFunc() { io:println("I'm the after function!"); } // The first test function. @test:Config function testFunction1() { io:println("I'm in test function 1!"); test:assertTrue(true, msg = "Failed!"); } // The second test function. @test:Config function testFunction2() { io:println("I'm in test function 2!"); test:assertTrue(true, msg = "Failed!"); } // The third test function. @test:Config function testFunction3() { io:println("I'm in test function 3!"); test:assertTrue(true, msg = "Failed!"); }
Each test case
The before
attribute of the @test:Config
annotation
The ‘before’ field in the test config annotation can be used to specify the function to execute before the particular test is run.
Example:
@test:Config {before: testFunction1} function testFunction3() { io:println("I'm in test function 3!"); test:assertTrue(true, msg = "Failed!"); }
The after
attribute of the @test:Config
annotation
The ‘after’ field in the test config annotation can be used to specify the function to execute after the particular test is run.
Example:
@test:Config {after: testFunction3} function testFunction2() { io:println("I'm in test function 2!"); test:assertTrue(true, msg = "Failed!"); }
Ensure test execution order
The test config annotation makes use of dependsOn
to indicate the specific test cases that the current test relies upon. This is beneficial for guaranteeing the correct sequence of test execution by specifying the required dependencies.
Example:
@test:Config {dependsOn: [testFunction4]} function testFunction5() { io:println("I'm in test function 5!"); test:assertTrue(true, msg = "Failed!"); }
Define test-specific configurations
Configurations for testing can be provided using configurable variables. The values for configurable variables can be
provided in a file named Config.toml
located in the tests
directory, which will only be initialized when the tests
are run.
Configurable variables can also be provided as command-line arguments when running the tests. The configurable values can be passed with bal test
in the format -Ckey=value
where key
is the configurable variable name and value
is the value to be assigned to the configurable variable.
Example:
$ bal test -Cval1=add -Cval2=10 -Cval3=5
Configurable variables are useful when you require separate configurations that cannot be feasibly used outside of testing. This is particularly useful when testing services and clients where you may need different host values when you are trying to test the service or client.
Define test-only dependencies
Dependencies are meant to be resolved only during testing and can be specified in the Ballerina.toml
file by specifying the
scope.
[[platform.java11.dependency]] path = "/user/foo/libs/abc.jar" scope = "testOnly"