Test Templates
Getting Started
The test template function helps extract some common test and infrastructure code to reusable components. In particular, it is useful for testing class hierarchies.
To create a test template, place the @TestTemplate macro above the abstract class.
@TestTemplate
abstract class DbTest {
public prop dbConnection: DbConnection
@TestCase
func testCommonDbApi1() { /* ... */}
@TestCase
func testCommonDbApi2() { /* ... */}
}
You can use this template to create multiple actual test suites, such as testing connections to different specific databases. To use the test template, you only need to inherit the corresponding class.
@Test
class MySqlTest <: DbTest {
var dbConnection_: ?DbConnection = None
override prop dbConnection: DbConnection {
get() {
dbConnection_.getOrThrow()
}
}
@BeforeAll
func initializeConnection() {
dbConnection_ = Some(...)
}
@AfterAll
func closeConnection() {
dbConnection_.close()
}
@TestCase
func testSpecificlyMySqlFeatures() {
/* ... */
}
}
Each test case will run as if it were written in the actual test class. The result is as follows:
------------------------------------------------------------
TP: default, time elapsed: 177679 ns, RESULT:
TCS: MySqlTest, time elapsed: 157163 ns, RESULT:
[ PASSED ] CASE: testCommonDbApi1 (34704 ns)
[ PASSED ] CASE: testCommonDbApi2 (8480 ns)
[ PASSED ] CASE: testSpecificlyMySqlFeatures (8329 ns)
Summary: TOTAL: 3
PASSED: 3, SKIPPED: 0, ERROR: 0
FAILED: 0
------------------------------------------------------------
The test template can be built using other test templates.
Lifecycle Methods
The test template can also contain some lifecycle methods, such as @BeforeAll, @AfterAll, @BeforeEach, and @AfterEach. Lifecycle methods are executed in the specified sequence:
- The
@Before_lifecycle method is executed in the sequence from the base class to the inheritance class. - The
@After_lifecycle method is executed in the sequence from the inheritance class to the base class.
The @_Each derived methods are also applicable to the test cases of the base class.
@TestTemplate
abstract class BaseTemplate {
@BeforeEach
func baseBeforeEach() { println("base before each") }
@AfterEach
func baseAfterEach() { println("base after each") }
}
@TestTemplate
abstract class Template <: BaseTemplate {
@TestCase
func templateCase() { println("template case") }
}
@Test
class Test <: Template {
@BeforeEach
func beforeEach() { println("before each") }
@AfterEach
func afterEach() { println("after each") }
@TestCase
func testCase() { println("case") }
}
The output is as follows (when output capture is enabled):
------------------------------------------------------------
TP: default, time elapsed: 456925 ns, RESULT:
TCS: Test, time elapsed: 456925 ns, RESULT:
[ PASSED ] CASE: templateCase (38228 ns)
STDOUT:
base before each
before each
template case
after each
base after each
[ PASSED ] CASE: testCase (16098 ns)
STDOUT:
base before each
before each
case
after each
base after each
Summary: TOTAL: 2
PASSED: 2, SKIPPED: 0, ERROR: 0
FAILED: 0
------------------------------------------------------------
Configuration
@Configure can be placed above the test template class, but @Configure of the inheritance class overwrites the value placed for the base class. All test cases are executed under the combined configuration.
Rules for Feature interactions
@Parallelcannot be used together with@TestTemplate.@Typescannot be used together with@TestTemplate.@Benchcan be used in templates and executed when--benchis specified as if the benchmark is placed in the inheritance class.