Automation Testing Framework

With the Automation Testing Framework, you can test the logic of scripts that use the published APIs. It supports writing tests with common frameworks like JUnit or Spock and running them with DaVinci Configurator 6’s features. It provides possibilities to write tests with a common testing framework (like JUnit or Spock) and execute them with the functionality of the DaVinci Configurator 6.

How to enable the testing framework

Closure for testing framework
scriptProject {
    //Path to the CFG
    cfgPath = file("${cfgPath}")

    classes = ["MyScript"]

    bswmd {
        bswPath = file("${bswPath}")
    }

    //Test Execution
    testing{
        bswPath = file("${bswPath}")
    }
}
This testing closure is used to configure the Automation Testing Framework. This method allows to set up the testing environment, such as BSW path and other testing parameters. If this method is called, testing will be automatically enabled for the script project.

Additionally the testing dependencies have to be added.

See chapter Managing Dependencies for more information.

Source Set 'testCfg'

The testing framework is based on the testCfg source set[1], which is automatically enabled when you activate the testing framework in your project.

See How to enable the testing framework for more information. In addition to the testCfg source set, the standard test source set can be used without script support.

Gradle Task 'testCfg'

To run the tests, you can use the gradlew testCfg command. This gradle task will execute all tests in the testCfg source set. The testCfg task will automatically get executed when you run the build task.

Writing basic tests

You can write tests using a common testing framework of your choice. While Spock is the preferred method, JUnit works as well. These tests must be located in the src/testCfg directory of your script project.

In the example GetDpaProjectNameTest you see a Spock test that uses a DaVinci Configurator 6 project to test the functionality of a script. Using DaVinci Configurator 6 projects in your tests can be simplified by an annotation, which is described in chapter sec:TestProjectLoadAnnotation.

Spock Example with usage of ScriptApi to read project name from DPA file
class GetDpaProjectNameTest extends Specification {

    @Shared
    IProjectRef projectRef = ScriptApi.scriptCode.projects.parameterizeProjectLoad {
        it.projectFile = Paths.get("%CFG_PROJECT_PATH%")
    }

    @Shared
    @TestProjectLoad
    ITestProjectRef projectRefExtShared = ITestProjectRef.forProject(projectRef)

    def "Test read project name"() {
        when:
        String origin = GetProjectName.getDpaProjectName()

        then:
        origin == "WorkshopProject"
    }

    static String getDpaProjectName() {

        def name = ""
        ScriptApi.scriptCode {
            projects.activeProject {
                name = project.getProjectName()
                scriptLogger.info("Work with the project: " + name + ".dvjson")
            }
        }
        return name
    }

}

The %CFG_PROJECT_PATH% placeholder must be replaced with the path of the DaVinci Configurator 6 project you want to test.

Plugin configuration

Following properties can be set in the testCfg configuration:

The cfgPath property specifies the path to the DaVinci Configurator 6 which should be used to run the tests. The bswPath property specifies the path to the BSW package which is used to run the tests. The additionalVmArgs property allows you to specify additional JVM arguments for the test execution.

Managing Dependencies

For adding test dependencies to your project, you should use the testCfg configuration.

Dependencies for testing framework
testCfgImplementation libs.spock
    testCfgImplementation platform(libs.junitBom)
    testCfgImplementation libs.junitApi
    testCfgImplementation libs.junitEngine

The template contain some of them with a compatible version in the libs.version.toml file, so you can use them directly in your build.gradle file.

Minimal Supported JUnit Platform Version

The minimal supported version of junit platform is 1.10.0, which is contained in junit bom version 5.10.0.

Testing API

Model TestInfrastructure

The ITransactionUndoAllExtension class provides a JUnit Extension, which will undo all transaction after the JUnit test was executed. This can be used as static or instance field to undo for the whole test class or for each test case.
Note: This extension does not work with Spock.

public class ProjectLoadTest {
    @RegisterExtension
    static ITransactionUndoAllExtension extension = ITransactionUndoAllExtension.forActiveProject(); // Undo changes after ALL test cases.
public class ProjectLoadTest {
    @RegisterExtension
    ITransactionUndoAllExtension extension = ITransactionUndoAllExtension.forActiveProject(); // Undo changes after EACH test case.
Usage of the ITransactionUndoAllExtension in a JUnit test
class TransactionUndoAllExtensionTest {
    @RegisterExtension
    ITransactionUndoAllExtension rule = ITransactionUndoAllExtension.forActiveProject();

    @Test
    void testcase() {
        //After this test case all transactions are reverted by the TransactionUndoAllExtension
    }
Setting the UndoHistoryLimit of the ITransactionUndoAllExtension in a JUnit test
class TransactionUndoAllExtensionWithLimitTest {
    @RegisterExtension
    ITransactionUndoAllExtension rule = ITransactionUndoAllExtension.forActiveProject(50);

    @Test
    void testcase() {
        //After this test case all transactions are reverted by the TransactionUndoAllExtension
    }

Automation Project TestInfrastructure

Load a Project in a JUnit Test

The IProjectLoadExtension class provides a JUnit 5 Extension, which will load the passed IProjectRef before test execution and close it afterward. This can be used as an JUnit 5 Extension.

public class ProjectLoadExtensionTest {
    @RegisterExtension
    static IProjectLoadExtension extension = IProjectLoadExtension.forProject(ScriptApi.scriptCode.projects.parameterizeProjectLoad{
        dpaFile "YourProject.dpa"
    })

    @Test
    public void testcase() {
        //In this test the project was loaded and will be closed after all tests.
    }

For details about the how to load a project, or if you want to load only an .arxml file, please refer to the AutomationInterfaceDocumentation.

Load a Project in a Spock Test

Use the TestProjectLoad spock annotation to load a test project. The internals will take care of opening/closing the project.
If you are using the spock.lang.Shared annotation, the given test project will be opened/closed once for the whole specification, meaning it will be shared over all feature methods.
If you don't use the spock.lang.Shared annotation, the given test project will be opened/closed after each feature method.

Note: This annotation needs as input an IProjectRef, which has to be provided by the ITestProjectRef.forProject, see example below.

@Shared
@TestProjectLoad
ITestProjectRef testProjectRefShared = ITestProjectRef.forProject(ScriptApi.scriptCode.projects.parameterizeProjectLoad { dpaFile = "./MyProject.dpa" })
With
testProjectRefShared.project
the IProject can be accessed.

Test and Debug productive Tasks with the Testing Framework

To test and debug a script task in a fast and convenient way, you can use the testing framework.
For this, a test will be set up that executes the task you want to test or debug. You can set breakpoints in your script and debug the test.
With the testing framework, you have control over the task execution environment. This means you can provide a bsw package, a DaVinci Configurator 6 project and user defined arguments.

Attention: Tests which executes a whole script task can take some time, especially if a project will be loaded. You can classify or disable these test with the common Spock/Junit mechanisms.

Test a DV_APPLICATION task

To call a DV_APPLICATION task:

Simple DV_APPLICATION script task
scriptTask("SimpleTask", DV_APPLICATION) {
    taskDescription 'Task description - Prints "HelloWorld" to console.'
    code {
        scriptLogger.info "!!!Hello World!!!"
        return "SimpleTask executed"
    }
}

You can write a spock test and test/debug the task:

Test for debugging a simple script task
def "Debug simple task"() {
    when:
    def result = ScriptApi.scriptCode().scripts.callScriptTask("SimpleTask")
    then:
    result == "SimpleTask executed"
}

Test a task with userdefined arguments

To call a task with userdefined arguments:

DV_APPLICATION script task with user defined parameters
scriptTask("SimpleTaskWithParams", DV_APPLICATION) {
    def nameArg = newUserDefinedArgument("name", String, "My String Param")
    def value = newUserDefinedArgument("value", Integer, "My Integer Param")

    code {
        return "name: $nameArg.value, value: $value.value"
    }
}

You can write a spock test and test/debug the task:

Test for debugging a script task with user defined parameters
def "Debug task with params"() {
    when:
    def result = ScriptApi.scriptCode().scripts.callScriptTaskWithUserArgs("SimpleTaskWithParams", "--name=Hello --value=42")
    then:
    result == "name: Hello, value: 42"
}

Test a DV_PROJECT task

To call a DV_PROJECT task:

Simple DV_PROJECT script task
scriptTask("ProjectTask", DV_PROJECT) {
    code {
        activeProject().getProjectName()
    }
}

You can write a spock test and test/debug the task:

Test for debugging a script task that requires a project
def "Debug task with project"() {
    when:
    def result = ScriptApi.scriptCode().projects.openProject("%CFG_PROJECT_PATH%") { scripts.callScriptTask("ProjectTask") }
    then:
    result == "WorkshopProject"
}

Attention:
The project will not be saved by default. But if the script contains a saveProject call, the project will be saved and persisted. See