View on GitHub

Aerial

Aerial Extension Development Guide

Download this project as a .zip file Download this project as a tar.gz file

Getting Started

Aerial is designed to be extensible and to cover various input and output formats. It should be extensible not only by internal design it should also provide an ability to include some external modules which can be easily used together with the entire engine. Mainly, it’s all about being able to create some kind of plug-ins. There are several areas where it can be done:

  • Input readers - components responsible for getting input data from some external source (any external system, file system etc.)

  • Output writers - components responsible for producing the output in some specific format

  • Scenario generators - components responsible for custom algorithms implementation which are targeted to produce new types of scenarios

  • Test Data generators - components targeted to implement various settings and algorithms for custom data types and corresponding input values generation process

All of the above component types implement specific interface and main things the Aerial needs are:

  • Configuration - the engine itself should be configured to use or include each specific module from specific location. Otherwise, it is decided that the component operates with built-in classes

  • Library availability in classpath - since we use Java and create some modules which are stand-alone libraries they definitely should be included into classpath before engine starts using it

All the above things are needed to be defined. On this page we’ll describe each of the component types in more details with examples of how to extend existing functionality in the direction of each specific component.

Custom Input Readers

Since version 0.0.4

Overview

All Aerial input readers are defined via classes extending AerialReader abstract class. Actually this class only defines default constructor and prototypes for core methods. They are:

Method Description
open Performs data initialization. Normally it identifies the scope of items to process and contains either some references or local copies of resources to read
close Cleans up all data and resets the entire reader
hasNext Used for iterative input elements processing. It indicates whether input source with settings specified contains more data
readNext Reads next portion of data from the specified source

Since all the above methods are pretty typical by their structure and functions they are used in typical way. Actually, all necessary set of actions are performed by AerialProcessor class so it is highly recommended to keep existing structure and approaches for AerialReader extensions.

Write Custom Reader

All classes inherited from AerialReader class should have constructor like:

1
2
3
public  AerialReader(AerialParams params, AerialTagList tagsValue) {
...
}

Tags handling isn’t really required. It is still desired feature but the actual tags handling is up to each specific implementation. There is no any specific interface for it. Actually, all user needs to do for tags is to fill their values depending on some rule. If tags are empty they simply won’t be used in generated files.

Configure Aerial to Use Custom Reader

Custom reader class can be passed as readerClass named parameter, e.g. readerClass=com.sample.CustomReaderClass. At the same time the input type parameter should be defined as CUSTOM.

Custom Output Writers

Since version 0.0.4

Overview

All Aerial output writers are defined via classes extending AerialWriter abstract class. It is abstract class defining common methods which should be implemented by any writer class. They are:

Method Description
open Initializes internal data. Normally this method is designed to take the list of parsed documents and set the reference to iterator so that engine will use it when processing each document items iteratively
close Closes and removes all internal data. Mainly it is invoked after entire writing is done
writeNext Used for iterative output elements processing. It takes next available document item and writes it to specific output in specific format. Main output is the string containing final representation of the generated text
hasNext Used for iterative processing. Indicates whether writer has more document items to process

Write Custom Writer

Configure Aerial to Use Custom Writer

Custom writer class can be passed as writerClass named parameter, e.g. writerClass=com.sample.CustomWriterClass. At the same time the output type parameter should be defined as CUSTOM.

Custom Types Definition

Since version 0.0.5

Overview

In some cases we have some data which is either very specific to application under test or it is some data which is logically grouped and you need to apply data generation for that using some specific rules. This is the case where built-in types are not enough and we need to use some custom type. For instance, we can create some custom type to operate with address which is the combination of strings and numbers in specific order.

Write Custom Input Type

Every custom type should be an extension of ValueExpression class. In this class we should override the following methods:

Method Description
public String getMatchPattern() Returns the regular expression which should be the pattern for any acceptable value of this type. In other words all positive values of this type should match the pattern
public String getValueTypeName() Returns the name of the custom type. This name should then be used in input data table
public List generate() Returns the list of generated data

Here is an example of custom input type:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.github.mkolisnyk.aerial.datagenerators;

import java.util.ArrayList;
import java.util.List;

import com.github.mkolisnyk.aerial.document.InputRecord;
import com.github.mkolisnyk.aerial.expressions.ValueExpression;

public class CustomExternalTypeExpression extends ValueExpression {

    @Override
    public String getMatchPattern() {
        return "(.*)";
    }

    @Override
    public String getValueTypeName() {
        return "Season";
    }

    public CustomExternalTypeExpression(InputRecord inputValue) {
        super(inputValue);
    }

    @Override
    public List<InputRecord> generate() throws Exception {
        List<InputRecord> result = new ArrayList<InputRecord>() {
            {
                new InputRecord(
                        getInput().getName(),
                        getInput().getType(),
                        "Winter",
                        getInput().getCondition(),
                        true);
                new InputRecord(
                        getInput().getName(),
                        getInput().getType(),
                        "Spring",
                        getInput().getCondition(),
                        true);
                new InputRecord(
                        getInput().getName(),
                        getInput().getType(),
                        "Summer",
                        getInput().getCondition(),
                        true);
                new InputRecord(
                        getInput().getName(),
                        getInput().getType(),
                        "Autumn",
                        getInput().getCondition(),
                        true);
                new InputRecord(
                        getInput().getName(),
                        getInput().getType(),
                        "Unknown",
                        getInput().getCondition(),
                        false);
            }
        };
        return result;
    }
}

In some cases we may need to define custom input type as an inner class. It can be done in the same fashion but with some restrictions: 1. That should be just a top level sub-class. So, inner class of inner class wouldn’t work 2. The container class should have default constructor

Configure Aerial to Use Custom Input Type

The list of classes representing custom types is defined either via aerial.types.custom.classes global property or via similar named system property. The value should contain canonical names as well as those classes should be available in the classpath.

Custom Scenario Generators

Since version 0.0.6

Overview

Besides standard generated scenarios Aerial provides an ability to extend case scenario generation engine to define specific scenarios which should be generated based on input.

Write Custom Scenario Generator

All custom scenarios must be an implementation of CaseScenarioGenerator class. Mainly we should implement the following methods:

Method Description
generate Returns final generated scenario or scenario outline. This is the main method which is being used by Aerial
isApplicable Returns true when this scenario is applicable for some specific data set. E.g. we may avoid the scenario generation if some specific test data attribute isn’t set
getScenarioName Returns string which defines suffix uniquely identifying the scenario name
getTags Returns the list of tags which should be applied to the scenario of current custom type

Configure Aerial to Use Custom Scenario Generator

The list of custom classes can be configured via aerial.gen.custom.classes configuration property or the same system property.

News