Skip to main content

Defining Test Models with Onion Specs

Onion specs are an API to define test models in a compact way. They are layered, like onions, to construct a hierarchical model.

In this example, you can see how a Component with 3 DataElements is constructed by nesting the specification methods:

component("testComponent",
dataElement("City"),
dataElement("Country"),
dataElement("District"));

Each specification methods has a similar signature:

public static ComponentSpec component(String specification, Spec... children) {}
  1. The first argument, specification, describes the element itself. Usually, it is the name of the element.
  2. After this, you can add any number of child specifications, which are then applied to the parent.

Setting Attributes/References​

To set an attribute other than name, we use CommonSpecs.set(attributeName, value).

E.g. to set the packageName of a DataElement:

import static net.democritus.spec.CommonSpecs.set;
//...
dataElement("City",
set("packageName", "net.demo.cities"))

References to other elements are defined with CommonSpecs.dataRef(referenceName, key).

E.g. to set the targetElement of a TaskElement:

import static net.democritus.spec.CommonSpecs.dataRef;
//...
component("testComp",
dataElement("City"),
taskElement("CityExporter",
dataRef("targetElement", "testComp::City")))
element keys

The notation used here to define the City dataElement is a functional key. It references the element by adding the name of the component. In the same way, we can reference a fieldFieldA property of a DataElement expanded to a database column and user interface input element. with testComp::City::postcode

Element Options​

Options can be added to elements using option("name: value").

dataElement("City",
option("cruds.table.pageSize: 50"))

If the option does not require a value, use option("name") instead.

DataElements, Fields and Finders​

A dataElement can contain fieldsFieldA property of a DataElement expanded to a database column and user interface input element. and findersFinderA search specification combining field-operator pairs to execute standard data queries on a DataElement.. To reduce the complexity, fieldsFieldA property of a DataElement expanded to a database column and user interface input element. and findersFinderA search specification combining field-operator pairs to execute standard data queries on a DataElement. have a shorthand syntax:

dataElement("City",
field("postcode: String*"),
field("country: Country[Ln01]"),
field("/population: Long*"),
finder("findByPostcodeEq"))

In this example we have:

  • A ValueField postcode with ValueType String
  • A LinkField country with target element Country and LinkFieldType Ln01
  • A CalculatedField (recognized by the /-prefix) population with ValueType Long
  • A FinderFinderA search specification combining field-operator pairs to execute standard data queries on a DataElement. findByPostcodeEq with FieldOperatorPair postcode-eq, which is added based on the FinderFinderA search specification combining field-operator pairs to execute standard data queries on a DataElement.'s name
ValueType vs ValueFieldType

A ValueField can either be defined as field("name: valueType*") or field("name: valueFieldType"). The first variation (with *) will use the newer ValueType. The second variation will use the outdated ValueFieldType.

DataProjections​

To define a dataProjection, you can add referenceFieldsFieldA property of a DataElement expanded to a database column and user interface input element. and calculatedFieldsFieldA property of a DataElement expanded to a database column and user interface input element.. CalculatedFieldsFieldA property of a DataElement expanded to a database column and user interface input element. will have a syntax similar to the value-fieldsFieldA property of a DataElement expanded to a database column and user interface input element.. ReferenceFieldsFieldA property of a DataElement expanded to a database column and user interface input element. should contain the name of the fieldsFieldA property of a DataElement expanded to a database column and user interface input element. they are referencing.

dataElement("City",
field("postcode: String*"),
field("country: Country[Ln01]"),
dataProjection("AreaInfo",
referenceField("postcode"),
calculatedField("size: Long")))

DataCommands​

DataCommands can have connectorFieldsFieldA property of a DataElement expanded to a database column and user interface input element. which are defined the same as regular fieldsFieldA property of a DataElement expanded to a database column and user interface input element., except they cannot be calculated.

dataElement("City",
field("postcode: String*"),
field("country: Country[Ln01]"),
dataCommand("addDistrict",
set("hasTargetInstance", true),
connectorField("name: String*"),
connectorField("location: Location[Ln01]")))