apigeek-affirm

Executable English for Software Testing and more


Keywords
openapi, swagger, scripting, docs, mocha, chai, gherkin, BDD, Specification, Natural Language, Test, API, Yeoman, Selenium, RESTful, QA, XML, Behaviour, Driven, documentation, declarative, builder, generator
License
Apache-2.0
Install
npm install apigeek-affirm@1.4.5

Documentation

I want to prove that my APIs are working correctly

Testing the features of your APIs is simple with Apigeek Affirm.

You can write richly descriptive and capable test cases and re-use them in different environments.

Even better - tests are written in "executable natural language" - so every stakeholder can make sense of them.

I want to test my APIs

In a nutshell, Apigeek-Affirm is a testing tool for Web APIs that uses the english language to describe scenarios to test.

Behaviour Driven Development (BDD) is an emerging best practice for testing APIs.

When using Affirm, a story is known as a "Feature" and a functional test is called a "Scenario".

A Feature collects together related Scenarios.

Each Scenario describes the expected behavior and outcomes in a way that is both human and machine friendly.

Each scenario is described using the Gherkin syntax: GIVEN -> WHEN -> THEN

I want to see an example

Affirm will test every scenario that is grouped together into a set of "features".

Scenario: Test Google's homepage

Given I enable redirects
When I GET http://google.com/
Then response code should be 200

I want to involve diverse stakeholders in testing

Gherkin is human and machine readable - business analysts, testers, developers and robots can collaborate.

The tests can be created in any simple text editor.

They are invoked elegantly from the command line, Mocha, your IDE or build pipeline.

The results are nicely formatted to help debug or even to showcase that your API passes QA.

I want to use natural language to describe tests

The general BDD pattern to describe a scenario is:

GIVEN   some pre-condition
WHEN    an action is performed
THEN    an outcome is expected

This notation is commonly called "Gherkin". To improve readability, the keyword AND can be used instead in place of the verbs above.

The text following the keyword (GIVEN | WHEN | THEN) needs to match a pattern that is understood by Apigeek-Affirm.

The supported patterns can be found in the Affirm Vocabulary

I want to test drive Affirm

Apigeek Affirm is built using NodeJS. If you're new to node, pre-read Getting Started.

You install Affirm as a system-wide CLI command:

$ npm install apigeek-affirm -g

To run it simply type:

$ affirm

However, It won't do much until we provide some test scenarios.

I want to combine tests into scenarios

A scenario describes a test case - essentially it's a list of instructions and expectations.

The framework interprets each step in the scenario using the Gherkin Vocabulary.

Let's expand our initial example, into a hypothetical scenario.

Scenario: Test Google's homepage 

Given I enable redirects
When I GET http://google.com/
And I return this.response.statusCode==200 as ResponseSucceeded
Then response code should be 200
And header Content-Type should exist
And header Content-Type should contain text/html
And variable ResponseSucceeded should be true

Affirm reads the GIVEN | WHEN | THEN sentences to build up a test suite that initializes, executes tests and make assertions.

Note: The example deliberately contravenes best practice to showcase a few concepts.

1) Enable redirect handling. 2) Issue an HTTP GET request to Google. 3) Evaluate an arbitrary Javascript expression and store the boolean result in a variable called "ResponseSucceeded". 4) Test that the HTTP status code is 200 (after an initial 302 redirect) 5) Test that a Content-Type exists. 6) Test that a Content-Type contains "text/html". 7) Check that "ResponseSucceeded" variable was set to "true" in line 3. This is redundant since line 4 already makes same assertion.

I want to combine multiple scenarios

A group of related scenarios is called a "feature" test suite. A test suite is identified by it's ".feature" file extension.

For example: the "hello world.feature" file might look like this:

Feature: Verify that variables are working

  Scenario: Test Variable Assignment

    Given I set test to hello
    Then variable test should match hello

By default, affirm looks in the "./features" sub-directory.

If your tests are in a different location, you can use the "--tests" or "--feature" option to locate them.

I want to reuse test scenarios in different environments

We can inject the "protocol", "hostname", "port" and "basePath" parameters from CLI options or a configuration file.

So, our example Scenario can be re-written to specify the resource only:

    When I GET /

Then for each environment - we'd want to change the parameters.

By default:

{
    "protocol": "http",
    "hostname": "localhost",
    "port": "80"
}

When constructing URLs for HTTP commands, we use "{{protocol}}://{{hostname}}:{{port}}/{{basePath}}{{resource}}" as a URL template.

If we wanted to define "https://google.com:443" as our endpoint, we'd use a JSON config file that looks like this:

{
    "protocol": "https",
    "hostname": "google.com",
    "port": "443"
}

I want to re-use tests across multiple endpoints

Apigeek-Affirm was designed to support a declarative style so that tests are portable between dev, test and production environments.

To achieve portability, environment-specific properties can be declared in a "config" file.

By default, affirm will try to load a configuration file called "affirm.json" from your current directory.

If no file is found, then sensible default values are defined.

You can change the name of the file using the "--config <file" option.

In this way, your BDD tests are neatly abstracted from your runtime configuration.

To specify a custom configuration, use:

affirm --config config.json

If you omit the --config option, then the "affirm.json" file in the current folder will be used.

Supplying a different "config" file for each environment allows Feature tests to be re-used across multiple environments.

The config file supports setting the following:

A default target - hostname and port. Multiple target sets are supported.

A default user agent - credentials for multiple named agents can be supplied.

client certificates - multiple named certificates are supported for example: valid, expired, invalid.

Webhooks - asynchronous notifications sent to Slack when tests start, finish and fail.

I want my tests to authenticate

You can specify sets of credentials for authentication (login) using the "agent" directive:

    "agent": {
        "default": {
            "username": "someone",
            "password": "TEST"
        },
        "robot": {
            "username": "robot@example.com",
            "password": "TEST321"
        }
    }

This will configure two authentication agents - "default" and "robot". Each has separate credentials.

The Gherkin vocabulary you to use different agents to perform Basic Authentication.

Experimental support for OAUTH 2.0 is also implemented.

Authentication Vocabulary:

GIVEN I use basic authentication
    I login
    I authenticate
GIVEN I use basic authentication as $AGENT
    I login as $AGENT
    I authenticate as $AGENT
GIVEN I use OAuth2
GIVEN I use OAuth2 as $AGENT

So you login to a web service using:

GIVEN I login as robot

See the Affirm Vocabulary for details.

I want to test APIs that use 2-way TLS

If your server requires 2-way TLS, you can supply client certificates.

GIVEN I use a valid client certificate

You can refer to named certificates from within your scenarios.

    "certificate": {
        "valid": {
            "key": "../etc/certs2/client/app-client.key.pem",
            "cert": "../etc/certs2/client/app-client.crt.pem",
            "ca": "../etc/certs2/ca/root-ca.crt.pem",
            "passphrase": "test"
        }, 
        "expired": { ... }
    }

Certificate Vocabulary

GIVEN I use a $CERT client certificate
    I use an $CERT client certificate

See the Affirm Vocabulary for details.

I want to be notified when tests are run / pass or fail

Affirm can send you a web hook notifications via Slack.

To confirm it simply add a section to your JSON config file:

{ 
    "webhooks": {
        "slack": {
            "username": "affirm-bot",
            "channel": "#testing",
            "url": "https://hooks.slack.com/services/XXXXXXXXX/YYYYYYYY/ZZZZZZZZ"
        }
    }
}

Once you have an active Slack account then obtain a new Slack webhook URL

You will receive events when scenarios start, finish successfully or fail.

I have multiple / complex runtime environments

Most teams have multiple target environments such as "dev", "test" and "prod".

The config file supports a "target" definition that supports named environments.

An example that supports multiple targets, user agents and certificates:

{
    "protocol": "http",
    "hostname": "google.com",
    "port": "80",

    "target": {
        "google": {
            "protocol": "http",
            "hostname": "google.com",
            "port": "80"
        },
        "secure-google": {
            "protocol": "https",
            "hostname": "google.com",
            "port": "443"
        }
    },
}

You can switch to different targets using the command line options "--target "

{
    "protocol": "http",
    "hostname": "google.com",
    "port": "80",

    "target": {
        "secure": {
            "protocol": "https",
            "hostname": "example.com",
            "port": "443",
            "agent": {
                "default": {
                    "username": "my-test-robot@example.com",
                    "password": "TEST1234"
                }
            },

            "certificate": {
                "valid": {
                    "key": "../etc/certs2/client/app-client.key.pem",
                    "cert": "../etc/certs2/client/app-client.crt.pem",
                    "ca": "../etc/certs2/ca/root-ca.crt.pem",
                    "passphrase": "test"
                }
            }
        },
    },

I want to license apigeek affirm

This software is licensed under the Apache 2 license, quoted below.

Copyright 2016 Lee Curtis lcurtis@apigeek.me

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

[http://www.apache.org/licenses/LICENSE-2.0]

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.