Onion-specs

The onion-spec is a set of helper classes that can be used to define models to be used in tests. This chapter will explain some of the features of the specs.

Spec types

There are 3 types of specs:

  • ElementSpecs define a model for an element. They always have the same structure: <elementSpec>(<specification>, <childSpecs>...).
  • AttributeSpecs define a specific attribute of an element. They are created with set(<attributeName>, <value>)
  • DataRefSpecs define a link to another element. They are created with dataRef(<linkName>, <reference>)

To make this clearer, we’ll use the example of a dataElement:

A taskElement with name ‘MailReceiver’:

taskElement("MailReceiver")

Now let’s set the packageName attribute with an AttributeSpec:

taskElement("MailReceiver",
  set("packageName", "net.demo"))

Next, we can define a link to a targetElement:

dataElement("MailReceiver",
  set("packageName", "net.demo"),
  dataRef("targetElement", "testComp::Mail"))

The notation used here to define the Mail dataElement is a functional key. It references the element by adding the name of the component. In the same way, we can reference a field with testComp::Mail::subject

DataElements, Fields and Finders

A dataElement can contain fields and finders. To reduce the complexity, fields and finders have a shorthand syntax:

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

In this example we have:

  • a value field postcode with valueFieldType String
  • a link field country with target element Country and linkFieldType Ln01
  • a calculated field (recognized by the /-prefix) population with valueFieldType Long
  • a finder findByPostcodeEq with field-operator-pair postcode-eq, which is added based on the finder’s name

DataProjections

To define a dataProjection, you can add referenceFields and calculatedFields. CalculatedFields will have a syntax similar to the value-fields. ReferenceFields should contain the name of the fields they are referencing.

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

DataCommands

DataCommands can have connectorFields which are defined the same as regular fields, 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]")))