Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Concordia can use databases to retrieve test data or to set the testing environment up before or after running test scripts.
To reduce the number of downloaded packages, Concordia Compiler 2 does not install database drivers by default anymore - as version 1 did.
Use --db-install
plus the driver name. Example:
Available driver names:
Driver Name
Database
note
csv
CSV files
xlsx
Excel files
firebase
Firebase
ini
INI files
json
JSON files
Already installed
mysql
MySQL
adodb
MS Access
Windows only
mssql
MS SQL Server
postgres
PostgreSQL
sqlite
SQLite
Database drivers are installed as development dependencies of your application.
You can also install or uninstall them with NPM, prefixing the driver name with database-js-
. Example: npm i -D database-js-mysql
.
Use --db-uninstall
plus the driver name. Example:
Just uninstall and then install it again.
A Database
is global declaration. You must declare it once and then import its file in other features. Example:
A database can be referenced inside UI properties and Test Events by its name between [
and ]
. Example: [My DB]
. To reference a database table, separate the table name from the database name with with a dot (.
) - e.g. [My DB.profession]
. Let's see an example:
Instead of reinventing the wheel, Concordia uses SQL to query and modify databases and files. Even JSON and INI files can be queried with SQL.
In the example above, the property value
from the UI Element "Profession" indicates that its (valid) values are retrieved from the table "profession" that belongs to the database declared as "My DB". The test event Before Each Scenario
was declared to connect to the database, clean the table "profession", and then insert new records that the UI Element "Profession" will use.
Imagine a solution in which you can write software requirements using an Agile-style, restricted natural language and it automatically generates for you using effective testing techniques such as , , and and it can also use test data from . Well, that's Concordia. Its solution is composed by a metalanguage and a compiler.
Concordia is also who was the personification of "concord" or "agreement". The idea is that the metalanguage help users, stakeholders, and software teams to discussing and reaching an agreement about the software requirements. A shared understanding about the requirements is essential to create the right software.
Concordia allows you to focus on writing your application's business rules and defining its expected behavior for when users interact with it. Stakeholders, business analysts, testers, and programmers can now discuss the application using a single language, a single source of truth. Business-focused and testing-focused declarations are clearly separated, so you can discuss technological details only with the interested parties.
With Concordia, you can write both and requirements, although it produces only functional test cases. Because it adopts -style declarations, you don't have to write it so formally (like usually do) and you can use plain text - which is easy to evolve with your codebase.
We invite you to and see how it is easy to understand. It is currently available in English (en
) and Portuguese (pt
).
Concordia compiler mix techniques with and to understand declarations in Concordia Language - which uses restricted natural language. After detecting declarations, it infers test scenarios, test data, and test oracles to generate test cases in a framework-independent format (see the ). Finally, it uses a plug-in created for a specific testing framework to generate test scripts (that is, source code), execute them and read their results. You don't need to write code. And the compiler checks your declarations for logic errors and other possible problems.
Follow the to see it in action! 😉
Concordia compiler uses plug-ins to transform Abstract Test Cases (ATS) into test scripts - that is, into source code. Every plug-in can be implemented to generate source code for a specific programming language and testing framework - in Java, Python, Go, PHP or whatever the language you prefer. The generated source code is not tied to JavaScript or TypeScript.
See the and for your favorite programming language and testing framework.
Concordia Compiler uses plug-ins for:
setting the testing environment up;
generating and executing test scripts;
converting and reporting test results.
Every plug-in can generate test scripts for a different testing framework or programming language.
Notes:
(*) RTS means "Requires a ", that is, if it requires a testing server to run the test scripts (e.g., Selenium Standalone).
(**) Appium requires Java for testing web-based mobile applications or using the Android SDK.
codeceptjs-testcafe
uses the frameworks and , and works with probably any browser.
codeceptjs-playwright
uses the frameworks and ,
requires Node 10.14 or above, and works with Chromium, Firefox, and Safari.
codeceptjs-webdriverio
uses the frameworks and , and works with Chrome, Firefox, IE, and Edge.
codeceptjs-appium
uses the frameworks and , and requires some to work.
codeceptjs-testcafe
and codeceptjs-playwright
are only available for Concordia Compiler 2 or above.
Use --plugin-install
plus the plug-in name. Example:
You can also use NPM for installing a plug-in. In this case, you must prefix the plug-in name withconcordialang-
. Example: npm install -D concordialang-codeceptjs-testcafe
.
Just uninstall the plug-in and then install it again. Example:
Concordia has the following plug-in commands:
plugin-install
to install a plug-in
plugin-uninstall
to uninstall a plug-in
plugin-serve
to start a testing server using the plug-in
plugin
to use a plug-in
plugin-info
to show information about a plug-in
plugin-list
to list installed plug-ins
All but the latter command (plugin-list
) require a plug-in name.
You can omit the argument <plugin>
if you have a configuration file with the property "plugin"
defined.
Some plug-ins (WebDriverIO, Appium) require a testing server to execute test scripts. A testing server controls a browser or an emulator during tests.
We recommend to open a new terminal/console and then start the testing server:
Naturally, you must replace <plugin>
with the plugin name.
The testing server will remain open. To stop it later, type Ctrl
+ C
.
Whether your plug-in needs a testing server, start it beforehand.
You can use --no-run
to avoid running test scripts and use --no-result
to avoid reading the last report with test results. Test scripts will be generated but not executed.
You can use --no-script
to avoid generating test scripts. Only existing test scripts will be executed.
is a browser extension for Chrome and Firefox that converts recordings from (which is a - that is, it records all the actions that you perform while interacting with the application under test in order the reproduce them later) to Variant sentences. That's very handful for discovering elements' identification in web applications (e.g., their id
properties or their ) and obtaining Variant sentences with the corresponding interaction.
is a command-line tool that generates User Interface Prototypes (UIP) from Concordia features. It can help discussing features with stakeholders and accelerating their construction. Currently there is a customizable plug-in for HTML-based interfaces.
is a command-line tool that generates an HTML page with an interactive graph that shows features files' relationships.
PINTO, Thiago Delgado. Unifying Agile requirements specification quality control and implementation conformance assurance. 2018. Doctoral Thesis. Pontifical Catholic University of Rio de Janeiro, Informatics Department, 2018.
PINTO, Thiago Delgado; COSTA, Pablo Veiga; GONÇALVES, Willian Inácio. User Interface Prototype Generation from Agile Requirements Specifications written in Concordia. 2019. WebMedia'19: Proceedings on the 25th Brazilian Symposium on Multimedia and the Web, Rio de Janeiro, 2019. ACM. DOI:
Abstract actions recognized through Natural Language Processing
Concordia Language contains a set of meta-actions that can be used by different testing frameworks for generating test scripts. Concordia Compiler uses Intent Recognition (yes, like chatbots do) to understand sentences and extract the desired action to perform. Later these actions are sent to testing frameworks for conversion into commands.
Concordia actions are recognized in Variants, Test Cases, and Test Events.
The following list presents the available actions and gives some examples on how to use them in sentences. We expect that you do not have to memorize them but, instead, see the things you can do. Try to write the sentences the way you speak, using first person singular (I
) . When there is a UI Element in the sentence, embrace it with {
and }
, like {this}
. The compiler will tell you whether it cannot understand some sentence you wrote. If you think it should have understood something, . We'll try to augment the compiler's vocabulary to understand it the next time.
accept
Accepts a browser message or app message.
amOn
Indicates a webpage or screen in which it is expected to be at.
append
Adds a value to an element.
attachFile
Attaches a file. It selects a file and confirms its choice (e.g., clicks Open).
cancel
Cancels a browser message or app message.
check
Checks a checkbox.
clear
Empties an input field or browser cookie
click
Clicks on something in the screen.
close
Closes a tab, a set of tabs, or an app (mobile only).
connect
Connects to a database.
disconnect
Disconnects from a database.
doubleClick
Performs a double click on something.
drag
Drags and drops something to a widget.
fill
Indicates that a field is being filled. If desired, a value can be given. Otherwise, a value will be generated for the corresponding Test Case.
hide
Hides something.
install
Installs an app.
maximize
Maximizes a window or the browser.
move
Moves the mouse cursor to a place or element.
open
Opens something
press
Presses a key or key combination, separated by comma.
Some special keys (case sensitive!):
Add
Alt
ArrowDown
or Down arrow
ArrowLeft
or Left arrow
ArrowRight
or Right arrow
ArrowUp
or Up arrow
Backspace
Command
Control
Del
Divide
End
Enter
Equals
Escape
F1
to F12
Home
Insert
Meta
Multiply
Numpad 0
to Numpad 9
Pause
Pagedown
or PageDown
Pageup
or PageUp
Semicolon
Shift
Space
Subtract
Tab
pull
Extracts a device's resource from a path.
refresh
Refreshes/reloads the current page.
remove
Removes/uninstall an app by its internal name (mobile only).
resize
Resizes a window.
rightClick
Performs a right click on something.
run
Runs a console command or a database script (SQL command).
👉 Commands and SQL scripts must be declared between single quotes ('
), in a single line.
👉 SQL scripts must reference their database.
JSON and CSV as databases: INSERT accepts JSON objects or arrays as values. Example:
SQL commands are limited to SELECT, UPDATE, INSERT and DELETE. WHERE works well. JOINs are not allowed. GROUP BY is not supported. LIMIT and OFFSET are combined into a single LIMIT syntax: LIMIT [offset,]number
saveScreenshot
Takes a screenshot an saves into a file.
scrollTo
Scrolls to a certain element.
see
Indicates that something can be seen. You can also negate the sentence to indicate something cannot be seen.
select
Selects a value for an element.
shake
Shakes the device - MOBILE ONLY.
swipe
Performs a swipe action - MOBILE ONLY
switch
Switches to a certain iframe and back to the application page; OR
Switches to a certain tab; OR
Switches an app to native mode or web mode - MOBILE ONLY.
NOTE: When switching to an iframe, all the commands that follow it will be applied to it.
tap
Performs a tap on an element - MOBILE ONLY
uncheck
Unchecks a checkbox.
wait
Wait for something.
This example covers the generation of test data and oracles and the combination of features using states.
Let's suppose that we have to create two simple features for a web application: "Login" and "Add Product". After discussing them with stakeholders and the team, we created the following Concordia specification (see the two tabs):
These features could correspond to the following sketches:
The specification helps stakeholders, analysis, testers and developers to create a shared understanding about the application and its business rules. It helps with the requirements validation, knowledge documentation, project design, implementation and testing.
Different from Use Cases and other requirements specification formats, with Concordia you probably don't need to define different scenarios for validation. Instead of having to manually define a set scenarios for validation, you just need to define how the UI elements should behavior - in their declaration - and the compiler will generate different scenarios for you in the form of Test Cases. Whether your application has a lot of such rules, your team will certainly benefit from it.
<TO-DO (UNDER CONSTRUCTION)>
It will generate login.testcase
with the following content:
If a seed is not given, Concordia Compiler assumes the current date and time. The seed is always printed in the console so that you or your team can reproduce the same paths, test data, and test oracle that were able to expose a bug in your application. Here we are giving it for a sake of reproduction.
Using the same seed over and over again will make Concordia Compiler produce the same results. Options no-run
and no-result
avoid running the test scripts and getting execution results.
This will not generate test cases or test scripts, but it will execute them and get their results:
login.testcase
:
test/login.js
:
Whether you ran the test scripts above, you probably saw they fail. That's because they didn't find a web application running at http://localhost/login
or because the application was found but it did not match the expected behavior. You may adapt your application and run the tests again.
Concordia shows a report that indicates the failures' locations. They help you to decide if a failure was caused by the application under test (e.g., it did not behave as expected) or because of the requirements specification (e.g., it is outdated in relation to the application).
Now keeping your specification updated has a new clear benefit: you can use it to generate tests and discover existing defects in your application!
Informal specification
It makes the compiler to ignore a piece of text. Example:
Local declaration.
At most one declaration per file.
Take precedence over a CLI option or configuration file option.
They are:
#language: <value>
defines the document's language, where <value>
is an available language such as en
(English) or pt
(Portuguese).
#locale: <value> defines document's locale, where <value> is an available local such as en-US (USA English) or pt-BR (Brazilian Portuguese). NOT AVAILABLE YET.
Example:
A tag adds metadata to a declaration.
Local declaration.
Allowed more than one tag per language construction.
A tag starts with @
. Multiple tags can be declared in a single line. Examples:
Some tags can receive parameters. Examples:
A special tag changes the compiler's behavior. These are special tags:
@importance( <number> )
: indicates the importance of a declaration. The importance is as high as its number.
The above example will avoid generating invalid input values (e.g., "A") for testing the format of the Year.
Reserved for future use:
@global
makes a UI Element globally accessible. Global UI Elements must not have the same name. Local UI Elements (the default) overrides global UI Elements.
@extends( <name> )
A common tag is ignored by the compiler and aims to provide meaningful metadata for a declaration. Any tag that is not a special tag is considered a common tag. Examples:
@critical
may indicate that the current feature is critical for the project;
@issue(20)
may indicate that a feature (or scenario or variant) is being implemented in the Issue 20 from the Issue control system.
Desired behavior of a software system
Global declaration with unique name, at most one declaration per file.
Sentences are optional and are not used for generating test cases.
A Feature can be a piece of functionality or some needed, wished or distinguish characteristic of a system.
Example:
Feature sentences should try to describe the contribution that the Feature brings to the business addressed by the software system. They are optional, but recommended. Example:
In the above example the benefit to the business is to prevent unauthorized access.
The order of the sentences can vary. A <role>
is usually a type of user or stakeholder. A <capability>
is what the role wants to perform in order to achieve the <benefit>
, which often is the contribution to the business.
A certain state of the system
Used for generating test cases.
Remove any (Then
) sentences with a produced State; and
Replace any (Given
or When
) sentences with a required State by sentences from the Variant that can produce it.
Let's say that we have a simple Login feature like this:
Now let's suppose that a user has to be logged in to access its account details:
High-level, business-focused, usage scenario of a Feature.
Local declaration with a unique name.
One or more declarations per Feature.
Sentences are optional and are not used for generating test cases.
Example:
Template:
Test-oriented declaration that describes a possible interaction between a user and the system in order to accomplish a Scenario.
Local declaration, one or more per Scenario.
Sentences are used for generating test cases.
Example:
Things that can be part of Variant sentences:
Values such as "bob@example.com"
Numbers such as 123
Make sure that your preconditions are part of the group with Given
sentences.
Make sure that your actions are part of the group with When
sentences.
Make sure that your post-conditions are part of the group with Then
sentences.
Whenever possible, use a single Given
, a single When
and a single Then
sentence. Useand
for the other sentences.
Write a single action per sentence.
Do not use and
in the middle of a sentence (break it, instead).
Use an additional indentation for and
sentences.
Variant sentences can have widgets (of the user interface) denoted between <
and >
. Example:
Available locators:
Declaration block with constant values
Global declaration (can be used by other files).
At most one declaration per file.
A Constants
block can define one or more constants, preceded by a dash sign (-
). Both constant names and values are declared between quotes, except for numeric values - that can be declared without quotes. Example:
Constant values are accessible by their names between [
and ]
. Examples for the constants above:
Defines a data table that can be used by UI Elements' properties.
Global declaration (can be used by other files).
Zero, one or many declarations per file.
A table must have a unique name. Their rows are denoted between pipe (|
). The first row must provide the column names. Other rows must provide the corresponding data. Example:
Declares a database connection that can be used for test data selection
Global declaration.
Names are shared with Constants and Tables.
Allowed more than one declaration per file.
Property values must be declared between quotes ("
).
Example 1:
Example 2:
Properties:
Imports declarations from a
.feature
file
Local declaration.
Give access to the declarations from the imported file.
Examples:
Welcome to the Concordia 2 documentation! This page will help you to get started fast. If you run into problems, you can find help on our .
See in case you don't know it yet.
Concordia Compiler requires only version 12.20 (or above) and works on Linux, MacOS and Windows.
In this Quick Start, we'll create a simple specification of an interaction with a search page and use . Therefore, download it before continuing.
If you are starting a new project or whether your project does not have a file named package.json
, then run:
You can use NPM, Yarn or PNPM.
Install Concordia Compiler :
It will install version 2 that is in alpha stage, although stable.
Note that the needed package name is concordialang
(with lang
). After installing it, we'll always use npx concordia
to execute it.
Create the folderfeatures
:
Now create the file search.feature
withinfeatures
, with the following content:
About the file:
Feature and Scenario are high-level, business-focused descriptions about the problem to solve. Their sentences are not used to generate test cases. The above example does not describe them.
A Variant describes the expected interaction with the application's user interface (UI) in order to perform a Scenario. Thus, a Variant uses technological vocabulary.
In Concordia, all the interactions with the UI use first person singular ("I"). That "I" represents the actor that is interacting with the application (in the example above, a visitor).
Finally, run
It will:
set the testing environment up (once);
generate a test case file and transformed it into a test script file;
execute the test script file; and
report the test script results.
Your browser should open automatically during this process and the console will report the execution results.
Your directory should now look like this:
The file features/search.testcase
should look like this:
The Test Case
above was produced from the Variant
declared in features/search.feature
. Some notes about it:
The import
clause (line 5) imports the declared file's content.
The tag @generated
(line 7) indicates that the Test Case was produced automatically.
The tag @scenario(1)
(line 8) indicates that the Test Case belongs to the first Scenario (1).
The tag @variant(1)
(line 9) indicates that the Test Case belongs to the first Variant (1) of the Scenario declared previously.
The Test Case
(line 10) is named using the Variant's name plus dash (-
) and some (incremental) number. Its content is basically the same as the Variant's, since we did not use any other declarations.
The file test/search.js
contains the test script produced from features/search.testcase
using the selected plug-in. It also contains line comments with references to their corresponding lines and columns in the .testcase
file:
You can opt to install Concordia Compiler locally (per project) or globally.
does not require administrative privileges (i.e., using sudo
on Linux or MacOS) to install;
allows every project to have its own, independent installation;
Global installation
requires administrative privilegies (i.e., using sudo
on Linux or MacOS) to install;
lets you execute the compiler direcly from any folder;
needs more attention when upgrading, especially for plug-ins.
Example:
Note: On Windows, you must omit sudo
.
Additional tips:
Whether Windows requires administrative privileges to install, right click Windows (Start) menu, click "Command Prompt (Admin)" or alternatively "Windows PowerShell (Admin)", and then proceed with the installation command.
To upgrade Concordia later, change the installation command from install
to upgrade
.
Concordia Compiler's versions are based on .
Although Semantic Versioning is conceived for s instead of for applications, we adopt a very similar convention. Thus, changes become predictable and you can know, from the version numbers, when a version is no more compatible with a previous version.
Given a version MAJOR
.MINOR
.UPDATE
:
MAIOR
is increased when the Compiler or the Language is no more compatible with the previous version.
MINOR
is increased when adding functionality in a backwards-compatible manner.
UPDATE
is increased when there are fixes, little changes or little novelties - all of them backwards-compatible.
Examples:
0.2.0
is compatible with 0.1.0
0.1.1
is compatible with 0.1.0
1.0.0
is not compatible with 0.2.0
NPM upgrades without breaking compatibility (when MINOR
orUPDATE changes
).
For migrating a MAJOR
version (e.g., 1.x
to 2.x
) please read our .
To upgrade a local installation:
To upgrade a global installation:
👉 Whether you have a with the property plugin
defined, you can omit the plugin name from a command. Example:
The next sentence is for only:
The next sentence is for only:
👉 Available for only.
Concordia Compiler uses to access databases and files through SQL-like commands. The supported SQL syntax may vary from one database to another. Please see the .
Excel and Firebase databases: Syntax similar to JSON and CSV databases. However, it has some limitations, as pointed out in :
INI databases: INSERT and DELETE are not supported yet by . UPDATE example:
SQLite databases: Currently uses that doesn't persist the changes in the file (only in memory).
There is an that can generate User Interface Prototypes (UIP) from a Concordia specification. The current version has a plug-in to create HTML-based UIPs and it's really easy to adapt it for other technologies.
that a Variant
express a possible interaction between a user and the application in order to complete its (business-focused) Scenario
. lt follows the syntax and always uses the word "I
" to represent the user or user role denoted in the Feature
's description.
Let's run Concordia Compiler with a to produce the same results over and over again:
@scenario( <number> )
: references a by its index, starting at 1.
@variant( <number> )
: references a by its index, starting at 1.
@generated
: indicates that a was computer-generated.
@fail
: indicates that a should fail.
@ignore
: whether applied to a , the Variant will not produce Test Cases; whether applied to a it will not produce test scripts.
@generate-only-valid-values
: avoids that a 's property be used for generating values considered invalid. This is specially useful for using with masked input fields, in which the system does not let a user to type invalid characters on it. For instance:
Business-oriented sentences, written as a .
Concordia adopts a wide-spread template for describing them: . A User Story template goes like this:
Local declaration, only accepted insidesentences.
A State is denoted by a text between tilde (~
), such as ~a state~
, and must be written inside sentences. Example:
A can both produce or require states. A State is produced by a Then
sentence, like in the prior example. A State is required by a Given
or a When
sentence. For instance:
By declaring a required State, you're establishing a dependency among the current and the ones that can produce it. Since that State is often produced by a Variant from another Feature, you have to the corresponding Feature file. Concordia Compiler will only search for states from imported Feature files.
When transforming Variants into , Concordia Compiler will:
Whether there are different s that can produce a (same) required State, Concordia Compiler will be able to combine each of them with the current Variant, aiming to produce that explore different execution paths. For more information, please read the section .
Concordia Compiler will produce my-account.testcase
with a like the following, that includes sentences from both the features:
Business-oriented sentences that follow the template .
Test-oriented sentences that follow the template and first-person singular ("I").
A Variant must use the Given-When-Then template (see ) and first person singular ("I
") in its sentences. Concordia Compiler uses techniques to understand them.
See the in Variant sentences.
References to , such as [New Account Screen]
References to , such as {Name}
or {New User:Name}
.
, such as <#ok>
, such ~registered user~
Concordia adopts the well-known to locate widgets. Plugins convert these selectors to the format adopted by the testing framework.
Whether you are testing a web application, you may find useful. It's a browser extension - available for Google Chrome and Mozilla Firefox - that extends Katalon Recorder to save a recorded interaction as Variant
sentences. Using it may reduce the time needed to locate the widgets of an existing application.
Constants cannot have the same name of a or a .
Tables cannot have the same name of a or a .
Table declarations are transformed into in-memory tables that can be queried by UI Element properties for selecting test data. Tables can be queried using SQL. Like , their names must be referenced between [
and ]
. Example:
Database support needs installation of the corresponding drives. See for more information on how to install them.
Concordia Compiler will ask you about some preferences. Press Enter
to answer every question with their default values. It will create a configuration file named .concordiarc
and install the selected and .
That's it. Congratulations!
The directory node_modules
contains installed dependencies, like tools and frameworks, whose versions are managed with package.json
and package-lock.json
. The file codecept.json
has a basic configuration to run CodeceptJS with Google Chrome and you can to fit your needs.
Concordia Compiler can also generate and for you. All the test cases and test scripts receive line comments that detail the and reference declarations used to produce oracles and test data.
demands using before every command.
Follow the for a install installation.
is included in NodeJS 8.2.0 or above.
.
Locator
Purpose
Example
#
To find a widget by its id.
When I click on <#save>
.
To find a widget by its class.
When I click on <.btn-primary>
@
To find a widget by its name.
When I click on <@save>
~
To find a widget by its mobile name.
When I click on <~save>
//
To find a widget by its XPath.
When I click on <//form/div/button[1]>
(none)
To find a widget by its type.
When I click on <button>
type
Database type. Examples: "adodb"
, "csv"
, "firebase"
, "ini"
, "json"
, "mysql"
, "mssql"
, "postgres"
, "sqlite"
, "xlsx"
. See Using Databases for all supported types.
Yes
host
URL that indicates where the database is hosted.
Vary
port
Network communication port used to connect to the database. Whether not defined, the default database port will be used, according to the property type
.
No
name
Database name. Used when there is a database server (whose location is defined by the property host
) and the database is accessible by its name.
Vary
path
Database path. Used when the database is accessed through the file system, such as the types csv
, ini
, json
, sqlite
and xlsx
.
Vary
username
Username used to connect to the database. When not defined, the database's default user will be used, according to the property type
.
No
password
Password used to connect to the database. When not defined, the database's default password will be used, according to the property type
.
No
options
Database-specific connection options.
No
Name (concordialang-...)
Target platform
Needs Java?
RTS*
web
No
No
web
No
No
web
Yes, Java 8+
Yes
Android, iOS, Windows
It depends**
Yes
seed
Variant
Time is a crucial constraint in software development and software teams often need to focus their test efforts on the most important application paths.
⚠ UNDER CONSTRUCTION ⚠
In software testing, test coverage is some kind of metric that helps you to understand what parts of your application (or code) are exercised by your tests. The number of feasible paths through them grows exponentially with an increase in application size and can even be infinite in the case of applications with unbounded loop iterations. That is a problem called path explosion problem. Concordia Compiler deals with it by providing sets of combination and selection strategies, and trying to achieve full path coverage over time.
All the Features, Scenarios, and Variants are covered by default.
The CLI parameter --files
can filter the .feature
files to be considered.
The CLI parameter --ignore
can indicate the .feature
files to be ignored, when a directory is given.
The tag @ignore
can be used to mark a Feature
or Variant
to be ignored by the test generator. However, it can still be used by other Features or Variants.
The tag @importance (e.g., @importance( 8 )) can be used to denote the importance of a Feature. CLI parameters --sel-min-feature and --sel-max-feature can then be used to filter the features to be considered by the test generator. Example: concordia --sel-min-feature 7 makes the compiler considers the features with importance value of 7 or above. By default, all the features receive an importance value of 5.
Variants are selected and combined using State-based Strategies (see below).
All the UI Elements constraints are covered by default, using a set of Testing Techniques (see below).
In Concordia, you can declare a State in a Variant sentence using a text between tile (~
), like this:
There are three types of State:
Precondition: when declared in a Given
sentence;
State Call: when declared in a When
sentence;
Postcondition: when declared in a Then
sentence.
Both Preconditions and State Calls are considered required States. That is, they denote a dependency of a certain State of the system that needs to be executed. A Precondition needs to be executed before the Variant starts, and a State Call needs to be executed during the Variant's execution.
A Postcondition is a produced State, that is, a state of the system produced by a successful execution of a Variant. Therefore, whether something goes wrong during a Variant's execution, it will not produce the declared State.
When the current Variant requires a State, Concordia Compiler will look for imported Features' Variants able to produce it. To generate complete Test Cases for the current Variant, it will:
Select the Variants to combine;
Generate successful test scenarios for the selected Variants;
Select the successful test scenarios to combine;
Generate (successful and unsuccessful) test scenarios for the current Variant;
Combine the selected successful test scenarios with the test scenarios of the current Variant;
Transform all the test scenarios into test cases (i.e., valued test scenarios).
Steps 1 and 3 can adopt different strategies. Concordia Compiler let's you:
Parameterize how the Variants will be selected, using --comb-variant
; and
Parameterize how the successful test scenarios will be combined, using --comb-state
.
Available strategies for --comb-variant
:
random
: Selects a random Variant that produces the required State. That's the default behavior;
first
: Selects the first Variant that produces the required State;
fmi
: Selects the first most important Variant (since two Variants can have the same importance value) that produces the required State;
all
: Selects all the Variants that produce the required State.
Example:
Available strategies for --comb-state
:
sre
: Single random of each - that is, randomly selects a single, successful test scenario of each selected Variant. That's the default behavior;
sow
: Shuffled one-wise - that is, shuffles the successful test scenarios than uses one-wise combination.
ow
: One-wise selection;
all
: Selects all the successful test scenarios to combine.
Example:
Strategies that use random selection can take different paths every time they are used. Furthermore, they reduce considerably the amount of generated paths - i.e., it avoids "path explosion" - and thus the amount of produced test cases.
Full-selection strategies can be used for increase path coverage. Although, it also increases the needed time to check all the paths, which may be undesirable for frequent tests.
By default, Concordia Compiler uses random selection strategies.
Concordia Compiler can infer input test data from Variants, UI Elements, Constants, Tables, and Databases. The more constraints you declare, the more test cases it generates.
Adopted techniques to generate input test data include:
These are well-known, effective black-box testing techniques for discovering relevant defects on applications.
We call Data Test Cases those test cases used to generate input test data. They are classified into the following groups: RANGE
, LENGTH
, FORMAT
, SET
, REQUIRED
, and COMPUTED
. The group COMPUTED
is not available on purpose, since a user-defined algorithm to produce test data can have bugs on itself. Thus, one should provide expected input and output values in order to check whether the application is able to correctly compute the output value based on the received input value.
Every group has a set of related data test cases, applied according to the declared constraints and selected algorithms:
Group
Data Test Case
Description
RANGE
LOWEST_VALUE
The lowest value for the data type, e.g., lowest integer
RANDOM_BELOW_MIN_VALUE
A random value below the minimum value
JUST_BELOW_MIN_VALUE
The value just below the minimum value, considering the data type and decimal places if applicable
MIN_VALUE
Exactly the minimum value
JUST_ABOVE_MIN_VALUE
The value just above the minimum value, considering the data type and decimal places if applicable
ZERO_VALUE
Zero (0
)
MEDIAN_VALUE
The median between the minimum value and the maximum value
RANDOM_BETWEEN_MIN_MAX_VALUES
A random value between the minimum value and the maximum value
JUST_BELOW_MAX_VALUE
The value just below the maximum value, considering the data type and decimal places if applicable
MAX_VALUE
Exactly the maximum value
JUST_ABOVE_MAX_VALUE
The value just above the maximum value, considering the data type and decimal places if applicable
RANDOM_ABOVE_MAX_VALUE
A random value above the maximum value
GREATEST_VALUE
The greatest value for the data type, e.g., greatest integer
LENGTH
LOWEST_LENGTH
An empty string
RANDOM_BELOW_MIN_LENGTH
A string with random characters and random length, less than the minimum length
JUST_BELOW_MIN_LENGTH
A string with random characters and length exactly below the minimum length
MIN_LENGTH
A string with random characters and length exactly equal to the minimum length
JUST_ABOVE_MIN_LENGTH
A string with random characters and length exactly above the minimum length
MEDIAN_LENGTH
A string with random characters and length equal to the median between the minimum length and the maximum length
RANDOM_BETWEEN_MIN_MAX_LENGTHS
A string with random characters and random length, between the minimum length and the maximum length
JUST_BELOW_MAX_LENGTH
A string with random characters and length exactly below the maximum length
MAX_LENGTH
A string with random characters and length exactly equal to the maximum length
JUST_ABOVE_MAX_LENGTH
A string with random characters and length exactly above the maximum length
RANDOM_ABOVE_MAX_LENGTH
A string with random characters and random length, greater than the maximum length
GREATEST_LENGTH
The greatest length supported for a string (see Notes)
FORMAT
VALID_FORMAT
A value that matches the defined regular expression
INVALID_FORMAT
A value that does not match the defined regular expression
SET
FIRST_ELEMENT
The first element in the defined set or query result
RANDOM_ELEMENT
A random element in the defined set or query result
LAST_ELEMENT
The last element in the defined set or query result
NOT_IN_SET
A value that does not belong to the defined set or query result
REQUIRED
FILLED
A random value
NOT_FILLED
Empty value
COMPUTED
RIGHT_COMPUTATION
A value generated by the defined algorithm
WRONG_COMPUTATION
A value different from that generated by the defined algorithm
By default, the maximum length for randomly-generated string values is 500
. This value is used for reducing the time to run test scripts, since long strings take time to be entered.
You can set maximum length using the CLI parameter --random-max-string-size
. Example:
You can also set it in the configuration file (.concordiarc
) by adding the property randomMaxStringSize
. Example:
Data Test Cases (DTC) are selected for every declared UI Element and its properties. The more properties you declare for a UI Element, the more data you provide for Concordia Compiler to generate DTC.
Example of some evalutations:
When no properties are declared, FILLED
and NOT_FILLED
are both applied and considered as valid values;
When the property required is declared, NOT_FILLED
(empty) is considered as an invalid value;
When the property value is declared:
if it comes from a set of values (inclusing a query result), all the DTC of the group SET
are applied;
otherwise, ...
When the property minimum value is declared:
There is more logic involved for generating these values. ...
Let's describe a user interface element named Salary
:
When no property is defined or only the property data type
is defined,
We defined the property data type
as double
, since the default data type is string
.
Since few restrictions were made, Salary
will be tested with the test cases of the group REQUIRED
:
FILLED
: a pseudo-random double value is generated;
NOT_FILLED
: an empty value will be used.
Now let's add a minimum value restriction.
Some tests of the group RANGE
are now applicable:
LOWEST_VALUE
: the lowest possible double is used
RANDOM_BELOW_MIN_VALUE
: a random double before the minimum value is generated
JUST_BELOW_MIN_VALUE
: a double just below the minimum value is used (e.g., 999.99
)
MIN_VALUE
: the minimum value is used
JUST_ABOVE_MIN_VALUE
: a double just above the minimum value is used (e.g., 1000.01
)
ZERO_VALUE
: zero (0
) is used
Since 1000.00
is the minimum value, the data produced by the tests 1
, 2
, 3
, and 6
of the group VALUE
are considered invalid, while 4
and 5
are not. For these tests considered invalid, the behavior defined in Otherwise
, that is
is expected to happen. In other words, this behavior serves as test oracle and must occur only when the produced value is invalid.
Unlike this example, when the expected system behavior for invalid values is not specified and a test data is considered invalid, Concordia expects that test should fail. In this case, it generates the Test Case with the tag @fail
.
Now let's add maximum value restriction:
All the tests of the group RANGE
are now applicable. That is, the following tests will be included:
MEDIAN_VALUE
: the median between the minimum and the maximum values
RANDOM_BETWEEN_MIN_MAX_VALUES
: a pseudo-random double value between the minimum and the maximum values
JUST_BELOW_MAX_VALUE
: the value just below the maximum value
MAX_VALUE
: the maximum value
JUST_ABOVE_MAX_VALUE
: the value just above the maximum value
RANDOM_ABOVE_MAX_VALUE
: a pseudo-random double above the maximum value
GREATEST_VALUE
: the greatest possible double
The tests from 5
to 7
will produce values considered invalid.
Let's define a user interface element named Profession
and a table named Professions
from which the values come from:
Applicable test are:
FILLED
NOT_FILLED
FIRST_ELEMENT
RANDOM_ELEMENT
LAST_ELEMENT
NOT_IN_SET
The first two tests are in the group REQUIRED
. Since we declared Profession
as having a required value, the test FILLED
is considered valid but NOT_FILLED
is not. Therefore, it is important to remember declaring required inputs accordingly.
The last four tests are in the group SET
. Only the last one, NOT_IN_SET
, will produce a value considered invalid.
In this example, let's adjust the past two examples to make Salary
rules dynamic and change according to the Profession
.
Firstly, we add two columns the the Professions
table:
Then, we change the rules to retrieve the values from the table:
The reference to the UI Element {Profession}
inside the query, makes the rules of Salary
depend on Profession
. Every time a Profession
is selected, the minimum value and the maximum value of Salary
changes according to the columns min_salary
and max_salary
of the table Professions
.
CLI
Basic syntax is:
where:
A parameter between[
and ]
means that it is optional.
[dir]
is the directory that contains your .feature
files. Whether it is not informed, the tool searches all the subdirectories from the current path.
[options]
changes how the tool behaves.
You can run concordia --help
to see all the command line interface (CLI) options.
You need to use npx
before the commands if you opted for a local installation.
Indicates a configuration file
Alias: -c
By default the configuration file is loaded from the current directory.
Creates a configuration file and optionally installs plug-ins and databases.
This command asks about your preferences. By hitting Enter
without giving an answer, it will select the suggested (default) value. You can use Up
and Down
to navigate the answers and hit Enter
to select it. For multiple selection (when available), hitSpace
.
By using a configuration file (e.g. .concordiarc
) you avoid informing the configured parameters in the console/terminal. For instance, whether plugin
is defined in the configuration file, you don't need to inform --plugin
anymore.
CLI options take precedence over values from configuration files.
Add CLI parameters to the configuration file
The following example will consider the given directory
and add it to the configuration file:
Indicates the directory that has
.feature
and.testcase
files.
Alias: -d
When not given, it will search the current directory and all subdirectories recursively.
We strongly recommend to use it or set it in the configuration file.
Example:
This is equivalent to:
You can use it with --no-recursive
to disable recursive search.
Specifies
.feature
files to consider
Aliases: -f
, --files
Files must be separated by comma.
Whether the command also informs a directory (e.g. --directory
), it searches the files inside the directory. Example:
The example above will search for ./feature/f1.feature
and ./feature/f1.feature
.
Specify
.feature
files to ignore when a directory is informed
Alias: -i
Files must be separated by comma.
Disables recursive search when a directory is informed
The directories will be used by a plug-in. We strongly recommend that you specify them in a configuration file.
Specifies the directory for test reports and screenshots.
Alias: -O
Specifies the directory for test script files.
Alias: -o
Sets the default language to consider.
Alias: -l
The language code must have only 2 characters and needs to be one of the available languages.
Lists the available language codes.
Lists the available locales.
Just generates test scripts
Just verifies specification files
Just generates test cases
Just execute test script files
Avoids generating test scripts
Avoids processing specification files
Avoids generating test cases
Avoids reading test scripts' results
Avoids running test scripts
Use -x
to combine --no-run
and --no-result
Uses a verbose output
These parameters require a plugin (--plugin
) and some plug-ins may not support them.
Number of parallel instances to execute.
Alias: -I
Executes browsers in headless mode.
Alias: -H
Sets one or more test script files to execute
Aliases: -F
, --script-files
Files must be separated by comma.
Sets a text or regular expression to filter the files to execute
Alias: -G
Sets target browsers or platforms to execute
Alias: -T
Browser or platforms must be separated by comma.
You can omit the prefix concordialang-
from plug-in names. For instance, concordialang-codeceptjs-playwright
becomescodeceptjs-playwright
.
Uses the given plug-in (if installed)
Alias: -p
You can use it with -x
to avoid running test scripts and reading their output:
Shows information about an installed plug-in
Alias: --plugin-info
Installs a plug-in
Lists installed plug-ins
Starts a testing server for a plug-in
Alias: -S
The testing server will keep running. Thus, it's a good idea to open a separate terminal/console for it. To stop it later, type Ctrl
+ C
.
Uninstalls a plug-in
See Using Databases for the list of available databases.
Installs a database driver
Lists installed databases
Uninstalls a database driver
Maximum random string size to generate, when free values are allowed.
The default value is 500
.
Minimum random string size to generate, when free values are allowed.
The default value is 0
.
Random tries to generate invalid values.
When there is a set of valid values and any value different from those in the set is considered an invalid, random generation is used to produce an invalid value. This parameter defines how many tries to take. Usually it gets on the first try.
The default value is 5
.
Sets a random seed
Concordia Compiler can use random selection in its algorithms. By default, it generates the seed using the current date and time. Using the same seed makes the algorithms produce the same output (e.g., same values and paths). While that's interesting for reproducing a past behavior, we don't recommend it for finding new defects. Using new seeds, Concordia Compiler will select different test data, test oracles, and test paths over time.
You can also set the algorithms to use, in order to avoid random selection. Full combination (therefore full coverage of the requirements) can be achieved and it is recommend for complete checking before a new release. However, it may take some time to execute.
--comb-data
--comb-invalid
--comb-state
--comb-variant
You probably don't need to use them, unless you're facing problems to read files.
Sets the character(s) used for breaking lines.
Since by default the line breaker is detected automatically, this command may not be useful for you in most cases.
Note on line breakers:
Linux uses "\n"
MacOS uses "\r"
Windows uses "\r\n"
Sets the expected file encoding
Alias: -e
The default is utf8
. Possible values are:
ascii
latin1
ucs2
or ucs-2
utf16le
or utf-16le
utf8
or utf-8
Shows information about the compiler.
Shows the available commands
Verify if there is a newer version.
Shows the current version.
Migrations are only needed when upgrading to a major version. See Versions and Upgrade for more information.
To upgrade to a major version:
Uninstall the current version, e.g.: npm uninstall -D concordialang
Install the new version, e.g.: npm install -D concordialang
Now proceed as described below (depending on your current version).
Note: For a global installation, replace -D
with -g
.
1.x
to 2.x
1. Update your plug-in
Concordia 2 has a new plugin API, not compatible with plug-ins for Concordia 1. So uninstall your current plug-in and install a new one. Example:
Alternatively, you can install one of the new plug-ins then change your configuration file to use it. Example:
2. Install database drivers
Whether your Concordia specification access a database, you have to install the corresponding database driver. Concordia 2 does not install them by default anymore, as Concordia 1 did, aiming to reduce the amount of downloaded dependencies.
Concordia 2 has a new CLI option --db-install
to help with that. Example:
See Database Drivers to install the proper driver(s) for your application.
0.x
to 1.x
1. Update your configuration file, if needed
Whether you project has a configuration file .concordiarc
, open it with a text editor. If the file has a property "plugin"
with the value "codeceptjs"
, you must change it to "codeceptjs-webdriverio"
.
2. Install the new plug-in
You can install any of the available plug-ins, currently codeceptjs-webdriverio
or codeceptjs-appium
. Example:
Concordia Compiler uses plug-ins for generating test scripts, running them and reading their results.
A plug-in can...
be coded in JavaScript or any language that "transpiles" to JavaScript, such as TypeScript (recommended), Dart, or CoffeeScript.
generate code (test scripts) for any programming language or testing framework able to perform functional tests for web, desktop or mobile applications.
Its name must start with concordialang-
, for example: concordialang-my-awesome-plugin
.
It must be installable with NPM. We recommend you to publish it at NPM too.
It must implement the interface Plugin
from concordialang-plugin.
Its package.json
file must contain the property concordiaPlugin
, like in the following example:
Properties of concordiaPlugin
:
file: string
: Relative path of the file that contains an implementation of the Plugin
interface.
class: string
: Class (name) that implementsPlugin
.
serve: string
: Multi-platform console command to execute in order to start the testing server. Whether the testing framework does not need running a testing server, you can set something like echo \"Running a testing server is not needed.\"
.
A plug-in must deal with three tasks:
Transforming Abstract Test Scripts into test scripts (i.e., source code).
Executing the produced test scripts, regarding some execution options.
Transforming test execution results (produced by the testing framework) to the expected resulting format.
Let's get into the details on how to accomplish them.
Think of an Abstract Test Script (ATS) as an object to transform into source code. Basically, it contains a structure that represents the actions to be converted into commands of your preferred programming language.
For instance, consider the following action:
That could be converted to the following command in Codeception, for PHP:
Or to the following command in Cypress, for JavaScript:
Let's consider a more realistic example, starting with a Test Case in the hypothetical file feature1.testcase
:
That would probably produce an Abstract Test Script like this:
A plug-in for Cypress could generate the following code from the above object:
To help generating such commands, you can use some template library such as Mustache (recommended) or Handlebars.
You can observe that after every command there is a line comment containing the corresponding location in the .testcase
file. These comments will help to track the specification in case of test script failures.
To execute the produced test scripts, you can use the target framework API or run the tool. Your call.
For example, whether you chose to run Cypress through npx
and generate a report using Mocha JUnit Reporter, the command to run could be the following:
Now the plug-in needs to read the report and transform it into an object of the class TestScriptExecutionResult
that will be returned to Concordia Compiler.
For instance, the core of the plug-in for CodeceptJS reads the report from a JSON file generated by using CodeceptJS with Mocha Multi Reporters. The current implementation is available in the class ReportConverter
.
A plug-in must be able to track back the location of failures or errors in the corresponding .testcase
file from a test script. When a test script has a failure or an error, the report saves the stack trace where it occurred. For instance, tests/feature1.js:20:4
indicates, respectively, the file, line and column where the problem happened. You can use these data to read the line of the test script file and retrieve the line comment that contains the corresponding line in the .testcase
file.
You can use a regular expression to extract the data from the stack trace, like ReportConverter
did in the method extractScriptLocationFromStackTrace
. Then you can use the class FileInstrumentationReader
from concordialang-plugin to retrieve the location from the line comment. Example:
You can read these locations in the examples described earlier. Whether tests/feature1.js:7:8
is...
Retrieving the line 10
and column 4
fromfeature1.testcase
would give us:
In TestScriptExecutionResult
, both test failures and errors are represented as an exception
which includes the properties scriptLocation
and specLocation
.
We recommend you to follow these steps when creating a plug-in:
1. Open an issue to indicate that you are interested in developing a new plug-in for a certain testing framework or programming language. That is good way to make others aware of your work.
2. Choose a good name for your plug-in and check whether it registered at NPM. Remember that it must start with concordialang-
. We recommend that it includes the target framework, tools or language. Example: concordialang-selenium-python
to create a plug-in that generates test scripts for the Selenium framework and the Python language. You may use the opened issue (step 1) to get feedback about the name, if you wish.
3. Create a repository for it (e.g., at GitHub, GitLab, BitBucket) and clone the repository.
4. Create a NPM package with npm --init
.
5. Add the property concordiaPlugin
to your package.json
file.
6. Install concordialang-plugin as a dependency:
7. Add your files. We recommend the following structure, but you can adapt it as you wish. For example, if you use TypeScript, you will probably add a tsconfig.json
file. If you use Jest, your test folder will probably be named __tests__
. We also recommend you to add a .editorconfig
file and a .gitignore
file (the latter should include the folder node_modules
).
8. Implement the interface Plugin. We recommend you to take a look at other plugins that did a similar job and encourage you to unit test all your code.
9. Test it with the Concordia Compiler before publishing it. Create a simple project that uses your plug-in. You can use NPM to install your plug-in from a directory in your computer or your remote repository. For example:
10. Publish your plug-in at NPM after making sure that you are using Semantic Versioning. Congratulations! Tell everybody and ask for feedback! ✌
Ideas and proposals
Work in progress and issues:
Kanban Board (GitHub)
Issues (GitHub)
Yes, this project does not have a logo yet 😱. Designers interested in helping us (for free 🙏), please contact us on our Slack Channel or open an Issue.
The logo should reflect the idea behind the language:
Concordia is the name of a roman goddess who was the personification of "concord" or "agreement". The idea is that the metalanguage may help users, stakeholders, and the software team to discuss and to reach an agreement about the software requirements. This shared understanding is essential to the software construction.
The tool generates test cases and test scripts that verify if the application under test meets the specified functional requirements. Therefore, the idea of "verification" or "testing" could be in the logo.
Interested? See how to create a plug-in.
👉 Our next goal is a plugin for Cypress.
Suggestions:
PHP: Codeception (web)
Java: Selenium (web), Robotium (android), AssertJ Swing (desktop)
Python: Selenium (web)
Other programming languages or frameworks are welcome! 💖
This language construction is part of Concordia Language since the first version, but it was not implemented yet.
A Variant Background
defines steps that must be executed before all the Variants of a certain Scenario. Example:
MOTIVATION: It allows to keep initial, repeated steps in a common place.
Like this:
MOTIVATION: Simpler syntax.
Please see Issue #27.
MOTIVATION: It allows to perform visual comparison and detect related bugs.
To use the characters """
(three quotation marks) to denote a text content to be compared. Example:
MOTIVATION: It facilitates comparisons with text files or multiple-line strings.
To allow a given UI Element or UI Literal to match a certain Table.
Example 1:
Example 2:
In which Some Table
is declared like this:
It should make target table's rows to match the declared ones.
MOTIVATION: It facilitates the verification of expected data in tables from a user interface.
NOTES: Probably it requires to convert the Concordia Action to many abstract commands that verify every table row independently. Usually testing frameworks do not provide such kind of verification (for many rows at once).
Use Concordia 2 data and time expressions inside table rows. They must be written between `
or some other character. Example:
MOTIVATION: Concordia Language allows date and time expressions inside UI Properties. Using them inside tables can be useful.
States that vary according to some generated value. Example:
According to the selected user, it will produce a different State. For example, when "bob" is selected, the produced state will be admin is logged in
and when "joe" is selected, the produced state will be guest is logged in
.
Thus, Features could depend on static or dynamic states.
MOTIVATION: Making states more flexible.
To provide a Given sentence that requires one - and only one - of the provided states. Example:
MOTIVATION: It allows to perform a XOR operation with the given states using natural language, aiming at choosing one and only one of the given states.
To provide annotations parameterize a test combination strategy for a specific Feature.
For instance, to configure the combination of invalid values for a specific Feature:
The annotations should correspond to the CLI parameters.
MOTIVATION: Increase the flexibility of the test generation procedure.
Currently:
Proposal (to accept as valid):
Alternative proposal:
MOTIVATION: Make it easier to write/read SQL statements.
Select a Feature for Test Case generation, without having to include its dependencies:
by importance value
Select a Scenario for Test Case generation:
by importance value (tag @importance
)
Test Case for test script generation;
by importance value (tag @importance
)
Provide the option --watch
to generate .testcase
files when their corresponding .feature
file changes or an imported .feature
file changes. A new seed must be produced, except when explicitly provided (using --seed
or configuration file).
Concordia has language constructions that the Compiler does not support yet. Examples:
Variant Background: Implement Variant Background
, which is part of the Concordia Language but was not implemented yet by the Concordia Compiler.
Support the tag @ignore
in Features and Scenarios. Currently it is supported inVariant
s and Test Case
s. Whether added to a Feature or a Scenario, it would not generate Test Cases.
Consider global UI Elements
Make the tool processing UI Elements tagged with @global
.
Allow inheritance of UI Elements
Use @extends( <name> )
to extend another UI Element.
Example:
Multiple declared Tables per query: Allow a query to reference more than one table declared in the specification.
Multiple declared Databases per query: Allow a query to reference more than one database declared in the specification.
Test cases that explore SQL Injection: Using declared Databases and Queries to formulate Test Cases that generate strings with SQL Injection commands.
Test cases that use naughty strings as test data: Using a list of naughty strings as test data.
It is already possible to generate HTML or even PDF reports using the available plug-ins. However, these reports indicate the frameworks' results, not necessarily the ones from Concordia.
To provide the CLI parameter --report
for indicating the corresponding plug-in. Example:
which should be equivalent to
Create new projects for auto-completion plug-ins for text editors such as VS Code, Sublime Text, Atom, etc. Example for VS Code: gherkin-autocomplete.
Be able to run test scripts using Concordia from the IDE.
Create integration with Allure. Other reporters (e.g., Macaca Reporter) can be added further.
Keep some hash control or use Git information when available. Hashes can be stored in a .json
or .yml
file. Example:
NodeJS has made considerable progress since version 10.5
adding support to Worker Threads. Stable support for Worker Threads was added in version 12
LTS. Although, it would increase minimum requirements to install Concordia Compiler - currently it requires NodeJS 8.0
.
Information about breaking changes.
1.x
to 2.x
Please read Issue #56.
0.x
to 1.x
It changed the way that all the plug-in operations are handled. See Issue #34 for details.
The behavior of the following plug-in commands were affected:
COMMAND
NOW
BEFORE
plugin-list
It lists all the plug-ins installed for the application.
It listed all the plug-ins available in the compiler.
plugin-install
It installs a plug-in and its dependencies.
Only the plugin's dependencies were installed, since the plug-in was embedded in the compiler.
plugin-uninstall
It uninstalls a plug-in and its dependencies using npm
.
Only the plugin's dependencies were uninstalled, since the plug-in was embedded in the compiler.
plugin-info
It shows information about a plug-in installed for the application.
It shows information about a plug-in available in the compiler.
plugin-serve
It starts a testing server using a plug-in installed for the application.
It started a testing server available in the compiler.
👉 See the Command Documentation to know the commands' syntax.
No compatibility breaks.
External tools used by plug-ins are now installed locally, per project, instead of installed globally. Their direct execution (without using Concordia) is now possible through NPX. For instance, the command codeceptjs run test.js
must now be executed as npx codeceptjs run test.js
. This change also allows the installation of different versions of external tools, when needed.
Were there any changes in commands' syntaxes?
No, there were not.
Is my configuration file still compatible?
It depends. All the properties are still compatible, except for "plugin"
. Whether your configuration file has that property, you should update it.
Is it possible now to install or uninstall a plug-in with NPM ?
Yes, it is possible to do both now.
Concordia Compiler can use a configuration file in JSON format named .concordiarc
. You can generate it by running the following command:
You'll be asked about the desired configuration and then the file will be saved.
Example:
Configuration file's properties are similar to CLI parameters. The example above defines: "pt"
(meaning "Portuguese") as the default language; the directory "docs/features"
for features and test cases; the plug-in "codeceptjs-testcafe"
for generating test scripts; the directory "test/e2e"
for test scripts; and the directory "test/e2e/output"
for output files such as report files and screenshots.
CLI options take precedence over values from the configuration file
directory
Type
Default value
CLI option
string
"."
(current dir)
--directory
Directory to search for .feature
and .testcase
files.
Example:
recursive
Type
Default value
CLI option
boolean
true
--recursive
Use recursive directory search.
Example:
files
Type
Default value
CLI option
string or string array
(none)
--files
Files to consider, instead of considering directory
. The files must be separated by colon.
Example:
Another example:
We recommend you to configure the property directory
whether your project can have new files.
ignore
Type
Default value
CLI option
string or string array
(none)
--ignore
Files to ignore, considering the parameter directory
. The files must be separated by colon. Example:
extensions
To-Do
encoding
Type
Default value
CLI option
string
"utf8"
--encoding
File encoding of the files. Accepted values are:
utf8
or utf-8
latin1
ascii
ucs2
or ucs-2
utf16le
or utf-16le
Naturally, the files must be edited with the given file encoding.
To-Do
To-Do
To-Do
To-Do
To-Do
Category
Option
Data Type
Default value
Description
Files
directory
string
none
Directory to search for specification and test case files
recursive
boolean
true
Recursive directory search
encoding
string
"utf-8"
Default file encoding
extensions
array of string
[ ".feature" ]
File extensions to search
ignore
array of string
[]
Files to ignore
files
array of string
[]
Files to consider, instead of considering directory
Language
language
string
"en"
Default specification language
Plug-in
plugin
string
none
Plug-in to use
Processing
verbose
boolean
false
Verbose output
compileSpecification
boolean
true
Whether it is desired to compile the specification
generateTestCase
boolean
true
Whether it is desired to generate test case files
generateScript
boolean
true
Whether it is desired to generate test script files
executeScript
boolean
true
Whether it is desired to execute test script files
analyzeResult
boolean
true
Whether it is desired to analyze test script results
dirTestCase
string
same as features'
Output directory for test case files
dirScript
string
"./test"
Output directory for test script files
dirResult
string
"./output"
Output directory of test script results
lineBreaker
string
OS' default
Character(s) used to break lines in text files
Generation
caseUi
string
"camel"
String case used to identify UI Elements when their ids are not defined. Possible values are "camel"
, "pascal"
, "snake"
, "kebab"
, or "none"
.
caseMethod
string
"snake"
String case used for test scripts' methods. Possible values are "camel"
, "pascal"
, "snake"
, "kebab"
, or "none"
.
tcSuppressHeader
boolean
false
Whether it is desired to suppress header comments in test case files
tcIndenter
string
" "
Character(s) used as indenter for test case files
seed
string
current date and time
Randomic seed used by all the algorithms
randomMinStringSize
integer
0
Minimum size for random strings
randomMaxStringSize
integer
500
Maximum size for random strings
randomTriesToInvalidValue
integer
5
Tries to generate random values that are not in a set of values
Strategies
combVariant
string
"random"
Algorithm to select and to combine the Variants with the state needed by a certain Variant. Options are: "random"
to pick a random Variant, "first"
to pick the first one, "fmi"
to pick the first most important, or "all"
to combine them all.
combState
string
"sre"
Algorithm to select and to combine the Test Scenarios of every State of the selected Variants. Options are: "sre"
to select a random Test Scenario of every State, "sow"
to use the shuffled one-wise algorithm, "ow"
to use the one-wise algorithm, or "all"
to combine them all.
combInvalid
string
integer
"smart"
Number of UI Elements that will receive invalid data test cases at a time, e.g. 1
. String options are "none"
for no invalid values, "smart"
to let the compiler decide, "random"
to select a random number of UI Elements, "all"
to select all the invalid values.
combData
string
"sow"
Algorithm to combine data test cases. Options are: "sre"
to select a random data test case to combine, "sow"
to use the shuffled one-wise algorithm, "ow"
to use the one-wise algorithm, or "all"
to combine them all.
To cite Concordia in a paper, please cite its PhD Thesis:
PINTO, Thiago Delgado. Unifying Agile requirements specification quality control and implementation conformance assurance. 2018. Doctoral Thesis. Pontifical Catholic University of Rio de Janeiro, Informatics Department, 2018.
Concordia Compiler infers test cases, test data and test oracles from specification files written in Concordia and tries to cover a large number of paths that can expose defects in your application. Its approach keeps the specification relevant, up-to-date and more useful for stakeholders, testers, and developers than other documentation formats.
We recommend the following usage cycle:
Write or update your requirements specification with the Concordia Language and validate them with users or stakeholders;
Use Concordia Compiler for generating functional tests from the specification and running them;
If the tests failed, there are some possibilities:
a) You still haven't implemented the corresponding behavior in your application. In this case, just implement it and run the tests again.
b) Your application is behaving differently from the specification. In this case, it may have bugs or you or your team haven't implemented the behavior exactly like described in the specification.
Whether the application has a bug, we are happy to have discovered it! Just fix it and run the tests again to make sure that the bug is gone.
Otherwise, you can decide between changing your application to behave exactly like the specification describes, or changing the specification to match your application behavior. In the latter case, back to step 1
.
If the tests passed, great job! Now you can write new requirements or add more test cases, so just back to step 1
.
When you type concordia
, the compiler performs the following process:
It uses Natural Language Processing (NLP) to identify sentences' intent, which increases the chances of recognizing different writing styles.
It performs semantic analysis to check recognized declarations.
It uses the specification to infer the most suitable test cases, test data, and test oracles, and then generates .testcase
files in Concordia Language.
It transforms all the test cases into test scripts (that is, source code) using a plug-in.
It executes the test scripts with the plug-in. These test scripts will check your application's behavior through its user interface.
It reads and presents execution results. These results relate failing tests to the specification, in order to help you understanding the possible reasons of a failure.
Overview of the Concordia declarations:
A Feature
defines a desired behavior for the software, a piece of functionality that gives some business value. A Scenario
is a high-level usage scenario of a Feature
. A Feature can have many Scenarios.
Since Feature
and Scenario
are business-oriented declarations, they are not used by Concordia Compiler to generate test cases. You can write them freely. Although, we recommend you to use the User Story template for a Feature
and the Given-When-Then template for a Scenario
. Example:
This is the User Story template:
As a <role>
I would like to <goal to perform>
In order to <received benefit>
(or So that <received benefit>
)
And this is the Given-When-Then (GWT) template:
Given <some context or precondition>
When <some action is carried out>
Then <a result or postcondition is observed>
In the GWT template, additional sentences of each kind are written in the next line and receive the prefix and
.
Features and Scenarios must have a name, but their description are not required. Thus, you can write the above example like this (although we recommend against):
Feature files receive the extension .feature
. Only one feature per file is allowed.
A Variant
is a test-oriented declaration that describes a possible interaction between a user and the system in order to accomplish a Scenario
. You can write more than one Variant
for a same Scenario
.
A Variant
must use the GWT template and first person singular ("I
") in its sentences. Concordia Compiler uses Natural Language Processing (NLP) techniques to understand Variant
sentences, aiming to transform them into test cases. Example:
Concordia Compiler understands the sentences from line 7
to11
as being variations of the same action, fill
.
Of course, the vocabulary is limited. Although, you can extend it whether you need (by adding new synonyms to a specific dictionary file). Actions and common variations are documented and suggestions are always welcomed.
In the sentences above, the values were denoted between quotation marks, e.g. "bob@example.com"
. Numeric values are also accepted and do not need quotation marks. Example: 97
.
Widgets (of the user interface) are written between <
and >
. Example: <#email>
. Concordia adopts the well-known CSS query selectors to locate widgets, regardless the user interface (its plugins convert them to the format adopted by the testing framework). You can also use XPath (although some plug-ins may not accept it). Examples:
#
(hashtag) to find a widget by its id. Example: #email
.
(dot) to find a widget by its class, if applicable. Example: .colorful
@
(at) to find a widget by its name. Example: @pass
~
(tilde) to find a widget by its mobile name, if applicable. Example: ~pass
no prefixed characters, to find a widget by its type. Example: input
//
(double slash) to find a widget by its XPath. Example: //table/tbody/tr[1]
Whether you are testing a web application, you may find Katalon-Concordia useful. It's a browser extension - available for Google Chrome and Mozilla Firefox - that extends Katalon Recorder to save a recorded interaction as Variant
sentences. Using it may reduce the time needed to locate the widgets of an existing application.
A State is denoted by a text between tilde (~
), such as ~a state~
, and must be written inside Variant sentences only. Example:
A Variant can both produce or require states. A State is produced by a Then
sentence, like in the prior example. A State is required by a Given
or a When
sentence. For instance:
By declaring a required State, you're establishing a dependency among the current Variant and the ones that can produce it. Since that State is often produced by a Variant from another Feature, you have to import the corresponding Feature file. Concordia Compiler will only search for states from imported Feature files.
When transforming Variants into Test Cases, Concordia Compiler will:
Remove any (Then
) sentences with a produced State; and
Replace any (Given
or When
) sentences with a required State by sentences from the Variant that can produce it.
Whether there are different Variants that can produce a (same) required State, Concordia Compiler will be able to combine each of them with the current Variant, aiming to produce Test Cases that explore different execution paths. For more information, please read the section State Based-Combination.
Let's say that we have a simple Login feature like this:
Now let's suppose that a user has to be logged in to access its account details:
Concordia Compiler will produce my-account.testcase
with a Test Case like the following, that includes steps from both the features:
Concordia Compiler can optimize the combination among Features in order to reduce the amount of produced test cases and, therefore, the total execution time. You can also opt to get full coverage - which is ideal before releasing a feature.
A Test Case
represents a test case produced for a certain Variant
. Concordia Compiler can generate many Test Case
declarations from a same Variant
, each one covering different states, input combinations and oracles. The generation considers the following declarations:
Variant
states
UI Element
Constants
Table
Database
The simplest Test Case
is one whose sentences are exactly equal to the Variant
's. That's the case when the Variant does not use other declarations and it explicits all the input test data to use.
For comparison, whether we simply remove with "Bob"
from the sentenceWhen I fill <#name> with "Bob"
, Concordia Compiler will generate a pseudo-random value to complete the sentence, and it will be like this: When I fill <#name> with "A~!39esljdns so2u1 *ns%"
.
Concordia Compiler uses a single seed to generate pseudo-random numbers in its algorithms and values. Everytime it runs, a new seed is produced. You can set the seed using the CLI parameter --seed
. By setting the seed, the compiler will pick the same paths and produce the same values - which is desirable for reproducing the same behavior in the application under test, but not for discovering new defects.
Don't worry about writing Test Cases. Write Variants and let Concordia generates the Test Cases for you.
A UI Element
represents a user interface element and can denote its expected behavior through properties.
Although a Widget is easy to declare, it can have some shortcomings:
1) It can make a sentence hard to read, specially when it uses XPath or CSS locators.
For example, the sentence
does inform what the action really means. The same sentence with a UI Element reference becomes
Then the UI Element can be declared as:
Here locator
is a property that denotes how to find it in the UI.
2. It can be hard to maintain. When a Widget appears in more than one Scenario and its locator needs to change (e.g. you have changed it in the UI), you need to search and replace all its occurrences in the document. With a UI Element, you just need to change the property locator
.
3. It does not offer resources for test generation other than its locator.
A UI Element
offers properties that can describe the behavior related to it. These properties are used to infer the test data and test oracles to generate.
Example:
Concordia Compiler infers 6
possible test cases from the above declaration, applying different testing techniques.
These are the UI Element properties:
id
or locator
⇨ how to locate the widget
type
⇨ widget type, like textbox
, button
, etc.
editable
⇨ whether the UI Element is editable (or not)
data type
⇨ data type of an editable
UI Element
required
⇨ whether the UI Element is required (or not)
format
⇨ data format, denoted by a regular expression
value
⇨ defines how the value is produced
minimum value
⇨ defines how the minimum value is produced
maximum value
⇨ defines how the maximum value is produced
minimum length
⇨ defines how the minimum length is produced
maximum length
⇨ defines how the maximum length is produced
By default, declaring a UI Element without properties is the same as declaring it with:
id
or locator
equal to the UI Element name in camelCase (e.g., "Net Price" becomes "netPrice"). The adopted case is configurable.
type
equal to textbox
data type
equal to string
Concordia Compiler is able to guess some properties from the others. For instance, editable
is enabled when type
is a widget capable of receiving input data; data type
can be inferred from any attributed value; etc.
Another example:
Concordia Compiler infers 4
possible test cases from the above declaration, applying different testing techniques.
Please see the language reference for more details. Let's proceed with the other declarations for now.
A Import
declaration allows you to import declarations from another .feature
file. Example:
Imported declarations are Feature, Constants, Table, Database, and UI Element.
A Constants
block defines one or more constants. Every Constant holds an immutable value that is accessible through the declared name. Example:
Constants are accessed by their name between [
and ]
. Example:
Constants are global declarations and cannot have duplicate names. You can use them in UI Element
properties and Variant
sentences.
A Table
declares values in rows and columns to use in UI Element properties. Example:
Concordia Compiler infers 4
possible test cases from the above declaration, applying different testing techniques.
Note that SQL is used to select values from the declared table, which is denoted between [
and ]
(like Constants). Table names are global and share the same namespace as Constant names.
A Database
provides a way to indicate a connection to an existing database or file. Example:
Concordia Compiler infers 4
possible test cases from the above declaration, applying different testing techniques.
SQL is used to select values from a table or view from the declared database, which is denoted between [
and ]
. Its table or view names are separated by a dot (.
). Database names are global and share the same namespace as Tables and Constants.
In order to set the execution environment up, testers can define events that can run database commands or command-line scripts. These events can occur before or after Scenarios or Features:
Before Each Scenario
: executes before every test of each Scenario of the current Feature.
After Each Scenario
: executes after every test of each Scenario of the current Feature.
Before Feature
: executes once, before all the tests of the current Feature.
After Feature
: executes once, after all the tests of the current Feature.
Before All
: executes once, before all the tests of the application under test.
After All
: executes once, after all the tests of the application under test.
Test Events are written like Variants, using Given-When-Then. Since they usually perform actions, it is very likely to useWhen
in most sentences. Example:
Commands and database scripts are denoted between apostrophe ('
).
This page presents Concordia actions and their corresponding commands for some frameworks.
Help us improving this page. Send us a message on or open an Issue at . 💖
👉 Under construction.
This page tries to identify in which version of the Compiler a certain language construction became available.
👁🗨 "Planned" and "Available" refer to versions of the Compiler.
*=Not used yet. **=It may not be released, since it is not needed.
Construction
Planned
Available
#
0.1
0.x
#language
0.1
0.x
#locale
2.1
Not released yet.
@*
0.1
0.x
@scenario
0.1
0.x
@variant
0.1
0.x
@ignore
0.1
0.x
@importance
0.1
0.x*
@generated
0.1
0.x
@fail
0.1
0.x
@global
0.1
Not released yet.
@extends
0.1
Not released yet.
@category
0.1
Not released yet.**
@issue
0.1
Not released yet.**
@generate-only-valid-values
1.0
1.1
Feature
0.1
0.x
Scenario
0.1
0.x
Background
0.1
Not released yet.**
Variant
0.1
0.x
Variant Background
0.1
Not released yet.
~state~
0.1
0.x
Constants
0.1
0.x
Table
0.1
0.x
Database
0.1
0.x
UI Element
0.1
0.x
UI Element property locale
1.4
2.0
UI Element property locale format
1.4
2.0
UI Element properties with date and time expressions
1.4
2.0
Test Case
0.1
0.x
Before All
0.1
0.x
After All
0.1
0.x
Before Feature
0.1
0.x
After Feature
0.1
0.x
Before Each Scenario
0.1
0.x
After Each Scenario
0.1
0.x
Concordia
Action [+target]
Appium
CodeceptJS
Cypress
Playwright
Puppeteer
TestCafé
amOn
amOnPage
goto
check
checkOption
check
clear + element
clearField
N/A
clear + cookie
clearCookie
clearCookies
click
click
doubleClick
doubleClick
dblclick
fill
fill
N/A
focus
move
moveTo
moveCursorTo
trigger
hover
hover
hover
press
press
refresh
refreshPage
reload
resize
resizeWindow
setViewportSize
rightClick
rightClick
saveScreenshot
saveScreenshot
screenshot
scrollTo
scrollTo
scrollTo
select
selectOption
selectOption
switch + element
switchTo
N/A
switch + next tab
switchToNextTab
N/A
switch + previous tab
switchToPreviousTab
N/A
tap
tap
N/A
type
type
wait + seconds
wait
N/A
wait + element
waitForElement
waitForElement
uncheck
uncheckOption
uncheck