Xtext 2.14 adds support for JUnit 5

Unit tests written for Xtext DSLs are typically using Xtext’s testing infrastructure provided by the org.eclipse.xtext.testing bundle. Older tests might even still use the deprecated org.eclipse.xtext.junit4 bundle. Tests for DSLs need to inject a language specific IInjectorProvider with an @InjectWith annotation. Additionally a specialized JUnit runner, the XtextRunner, is used with the @RunWith annotation to run the test. 

An Xtext test therefore looks like this:

@RunWith(XtextRunner)
@InjectWith(MyDslInjectorProvider)
class MyDslSomethingTest {
...
}

The XtextRunner uses the injector provider, does the member injection into the class-under-test and takes care that internal registries are reset after test execution. This is required to avoid side effects from modifications on global EMF registries during test execution. However, JUnit runners are specific to JUnit 4 and therefore XtextRunner can only be used to run tests with JUnit 4. 

To support the new JUnit 5 framework Xtext needed something equivalent to what the XtextRunner does. In JUnit 5, additional logic that needs to be executed in a test’s lifecycle can be added with means of Extensions. JUnit 5 Extensions are more powerful than Runners. Especially there can be multiple of them, while you can only have a single runner.

The replacement for XtextRunner is the new class org.eclipse.xtext.testing.extensions.InjectionExtension. Use it together with the @ExtendWith annotation. So a typical test now looks as follows:

@ExtendWith(InjectionExtension) 
@InjectWith(MyDslInjectorProvider)
class MyDslSomethingTest {
...
}

That’s basically it to make tests run with JUnit 5! Easy, isn’t it?

In Eclipse, you can run them as you are used to with the Run As / JUnit Test action. Note that the test execution now shows that it was run with the JUnit 5 engine.

JUnit5-Test-Execution

JUnit 5 dependencies

Of course a testing project needs different dependencies with JUnit 5. The following dependencies are used in the test project’s MANIFEST.MF:

org.junit.jupiter.api;bundle-version="5.1.0", 
org.junit.jupiter.engine;bundle-version="5.1.0",
org.junit.platform.commons;bundle-version="1.1.0",
org.junit.platform.engine;bundle-version="1.1.0",
org.opentest4j;bundle-version="1.0.0",

When using Gradle add these dependencies to the build.gradle file in the test project:

dependencies {    
compile project(':org.xtext.example.mydsl')    
testCompile "org.junit.jupiter:junit-jupiter-api:5.1.0"    
testCompile "org.junit.jupiter:junit-jupiter-engine:5.1.0"    
testCompile "org.junit.platform:junit-platform-commons:1.1.0"    
testCompile "org.junit.platform:junit-platform-engine:1.1.0"    
testCompile "org.opentest4j:opentest4j:1.0.0"    
testCompile
"org.eclipse.xtext:org.eclipse.xtext.testing:${xtextVersion}"    
testCompile
"org.eclipse.xtext:org.eclipse.xtext.xbase.testing:${xtextVersion}"
}

If you are creating Eclipse plugins, JUnit 5.1 must be part of your target platform. That version has just recently been added to Eclipse Orbit and there is at the time of writing of this article just an integration build repository available hosting these bundles: http://download.eclipse.org/tools/orbit/downloads/drops/I20180417184143/repository
In the near future, use a more stable repository. That will be the recommended repository for Eclipse Photon, or before the Photon release, the repository for the Photon M7 milestone.

New Project Wizard

Xtext’s New Project Wizard now lets you decide which JUnit version you want to use for new projects.

new-Xtext-Project-Wizard


In the language’s .mwe2 workflow file the junitSupport will configured for version 5 then, which instructs Xtext’s generator to add the required dependencies to the test project and create the example parser test in JUnit 5 style.

JUnit5-Support

Migrating Tests

To migrate your Xtext tests to JUnit 5 the most important things have already mentioned above:

  • Make sure you add the JUnit 5 dependencies to your tests project
 
  • Replace @RunWith(XtextRunner.class) by @ExtendWith(InjectionExtensions.class)
 
  • Replace import org.junit.Test by org.junit.jupiter.api.Test
 
  • Replace import org.junit.Assert by org.junit.jupiter.api.Assertions


Conclusion

With Xtext 2.14 tests can be written and executed with JUnit 5. For new projects Xtext’s wizard produces the right configuration automatically. However, migration of existing Xtext test projects and classes is quite easy. 

About Karsten Thoms

Karsten is a software architect at itemis and part of the Xtext team. He strongly believes that Model Driven Software Development helps to be more efficient in mission critical projects.