Expanders Assert
ExpandersExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. assert is a library to test ExpandersExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. and Features. It improves on the expandersExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact.-test-utils library to fix a few long-standing issues:
- The expansionResource manifest for the project is generated ad hoc, which makes the tests more predictable.
- The framework actively checks for classpath conflicts and gives clear error messages.
There are also improvements which make it easier to create tests with new Metamodels:
- ExpandersExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact.-assert fixes issues with creating ExpansionContexts by using the same infrastructure that is used during expansion.
- Finding elements in your test models has been simplified by using the DataRegistry.
Setup
Add the following dependency to your expandersExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. project:
<dependency>
<groupId>net.democritus.test</groupId>
<artifactId>expanders-assert</artifactId>
<version>1.4.0</version>
<scope>test</scope>
</dependency>
The library is based on junit 5 with AssertJ. Add these to the test dependencies with:
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.26.3</version>
<scope>test</scope>
</dependency>
</dependencies>
ExpanderTest
Each ExpandersExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. test should be annotated with @ExpanderTest.
This will enable the junit 5 extensions to test the ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact..
import net.democritus.expander.junit.ExpanderTest;
@ExpanderTest
public class SampleExpanderTest {
}
By default, the test will look for an ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. with the same name as the test class minus the Test-suffix.
If the Test class name does not match the ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact., you can provide the name of the ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. in the @ExpanderTest annotation.
@ExpanderTest(name = "net.democritus.expander.SampleExpander")
FeatureTest
Feature tests (both for the feature itself and the ExpanderFeatures), should be annotated with @FeatureTest.
import net.democritus.expander.junit.FeatureTest;
@FeatureTest
public class MyFeatureTest {
}
The Feature (and ExpanderFeature) are resolved similarly to the ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact., based on the Test class name:
- If the Test class matches the Feature name (e.g.
MyFeatureTestforMyFeature), then it will select that feature and pick the first of its ExpanderFeature. - If the Test class matches the ExpanderFeature name (e.g.
MyFeatureBeanExpanderTestforMyFeature.BeanExpander), then it will select that ExpanderFeature and its Feature.
It is also possible to explicitly define the Feature and ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact..
@Feature(feature = "net.democritus.feature.MyFeature")
@Feature(
feature = "net.democritus.feature.MyFeature",
expander="net.democritus.expander.ejb3.dataElement.BeanExpander")
Test Model
Every test starts with a test model.
To define this model, create a method names baseModel() with the @TestModel annotation.
import net.democritus.expander.junit.ExpanderTest;
@ExpanderTest
public class SampleExpanderTest {
@TestModel(select = "testComp::City")
Spec baseModel() {
return component("testComp",
dataElement("City"));
}
}
The model is defined using Onion Specs. You can optionally define the select parameter to select an Element within the model.
TestExpansion
Each test method receives a TestExpansion instance. This object allows you to assert conditions of your ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact./Feature.
Testing Expanders
To test the results of an ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact., use testExpansion.assertThatExpander().
@ExpanderTest
public class SampleExpanderTest {
@TestModel(select = "testComp::City")
Spec baseModel() {
return component("testComp",
dataElement("City",
set("packageName", "net.demo.cities")));
}
@Test
void test_artifactPath(TestExpansion<DataElementComposite> expansion) {
/*
Test the result of the artifact path definition in the Expander XML file.
`$componentRoot.directory$` or `module.rootDirectory` will be translated to `C:/MODULE_ROOT`.
`$applicationRoot.directory` or `program.rootDirectory` will be translated to `C:/PROGRAM_ROOT`.
*/
expansion
.assertThatExpander()
.hasArtifactPath("C:/MODULE_ROOT/net/demo/cities/City.java");
}
@Test
void test_isApplicable(TestExpansion<DataElementComposite> expansion) {
/* Test isApplicable condition defined in the Expander XML file */
expansion
/* extendModel() allows you to add additional specifications to the model */
.extendModel(option("example.option"))
.assertThatExpander().isApplicable();
}
@Test
void test_isNotApplicable(TestExpansion<DataElementComposite> expansion) {
expansion.assertThatExpander().isNotApplicable();
}
@Test
void test_base(TestExpansion<DataElementComposite> expansion) {
/*
Test the base content generated by the expander.
*/
expansion.assertThatExpander().baseContent().matchesTemplate();
}
@Test
void test_anchor_fields(TestExpansion<DataElementComposite> expansion) {
/*
Test the `fields` anchor.
*/
expansion
.extendModel(
field("name: String"),
field("status: String"))
.assertThatExpander().anchor("fields")
.matchesTemplate();
}
}
Base Content
expansion.assertThatExpander().baseContent() allows you to match the content your ExpanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. generates.
To make testing more manageable, it is possible to put anchorsAnchorA marker within generated source code reserved for adding custom logic during re-expansion. around parts of the expanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. template.
When testing the base content, the content between those anchorsAnchorA marker within generated source code reserved for adding custom logic during re-expansion. is filtered out.
base() ::= <<
package <packageName>;
// <expanderComment>
public class <dataElement> {
@anchor:fields
// anchor:fields:start
<fields:{f|private <f.type> <f.name>;};separator="\n">
// anchor:fields:end
}
>>
test_base() ::= <<
package net.demo.cities;
// @expanderComment@
public class City {
// anchor:fields:start
// anchor:fields:end
}
>>
matchesTemplate will compare the content to a template in the ExpanderTest stg file with the same name as
this method (test_base in this case).
Both the expanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. template and expanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. test template are evaluated by the template engine. Because the \ character is
an escape character for this engine, it is required to escape that character twice in both templates if it occurs in the
artifactArtifactA build or deployment result, such as a Docker container image or Java archive, produced by a software project. that is being expanded.
Example: If an escaped backslash \\ is needed in a piece of expanded code because it occurs in a string, both the
expanderExpanderA unit of generation that combines a data tree instance (functional M1 model) with a template to generate an artifact. template AND test template must double escape it as \\\\.
Anchors
The content between anchorsAnchorA marker within generated source code reserved for adding custom logic during re-expansion. can be tested separately with expansion.assertThatExpander().anchor("fields"), fields
here being the name of the anchorAnchorA marker within generated source code reserved for adding custom logic during re-expansion..
test_anchor_fields() ::= <<
private String name;
private String status;
>>
Test Features
To test Features, we use testModel.assertThatFeature().
@FeatureTest
public class MyFeatureTest {
@TestModel(select = "testComp::City")
Spec baseModel() {
return component("testComp",
dataElement("City"));
}
@Test
public void test_isApplicable(TestExpansion<DataElementComposite> expansion) {
/* Test condition in Feature XML. */
expansion
.extendModel(option("example.feature"))
.assertThatFeature().isApplicable();
}
@Test
public void test_isNotApplicable(TestExpansion<DataElementComposite> expansion) {
expansion.assertThatFeature().isNotApplicable();
}
}
@FeatureTest
public class SampleFeatureSampleExpanderTest {
@TestModel(select = "testComp::City")
Spec baseModel() {
return component("testComp",
dataElement("City"));
}
@Test
public void test_base(TestExpansion<DataElementComposite> expansion) {
/* Test the base content of the ExpanderFeature. */
expansion.assertThatFeature().baseContent().matchesTemplate();
}
@Test
public void testImports(TestExpansion<DataElementComposite> expansion) {
/* Test imports that were added with usage statements in the mapping file.*/
expansion.assertThatFeature().imports().matchesTemplate();
}
}