User's Guide
Reference Manual
Release Notes
PDF
Top

Common Test
User's Guide
Version 1.7.2

Expand All
Contract All

Chapters

- Common Test Basics
  - Top of chapter
  - Introduction
  - Test Suite Organisation
  - Support Libraries
  - Suites and Test Cases
  - External Interfaces
- Getting Started
  - Top of chapter
  - Are you new around here?
  - Test case execution
  - A simple test suite
  - A test suite with configuration functions
  - What happens next?
- Installation
  - Top of chapter
  - General information
- Writing Test Suites
  - Top of chapter
  - Support for test suite authors
  - Test suites
  - Init and end per suite
  - Init and end per test case
  - Test cases
  - Test case info function
  - Test suite info function
  - Test case groups
  - The parallel property and nested groups
  - Parallel test cases and IO
  - Repeated groups
  - Shuffled test case order
  - Group info function
  - Info functions for init- and end-configuration
  - Data and Private Directories
  - Execution environment
  - Timetrap timeouts
  - Logging - categories and verbosity levels
  - Illegal dependencies
- Test Structure
  - Top of chapter
  - Test structure
  - Skipping test cases
  - Definition of terms
- Examples and Templates
  - Top of chapter
  - Test suite example
  - Test suite templates
- Running Tests
  - Top of chapter
  - Using the Common Test Framework
  - Automatic compilation of test suites and help modules
  - Running tests from the OS command line
  - Running tests from the Erlang shell or from an Erlang program
  - Test case group execution
  - Running the interactive shell mode
  - Step by step execution of test cases with the Erlang Debugger
  - Test Specifications
  - Running tests from the Web based GUI
  - Log files
  - HTML Style Sheets
  - Repeating tests
  - Silent Connections
- External Configuration Data
  - Top of chapter
  - General
  - Syntax
  - Requiring and reading configuration data
  - Using configuration variables defined in multiple files
  - Encrypted configuration files
  - Opening connections by using configuration data
  - User specific configuration data formats
  - Examples of configuration data handling
  - Example of user specific configuration handler
- Code Coverage Analysis
  - Top of chapter
  - General
  - Usage
  - Stopping the cover tool when tests are completed
  - The cover specification file
  - Cross cover analysis
  - Logging
- Using Common Test for Large Scale Testing
  - Top of chapter
  - General
  - Usage
  - Test Specifications
  - Automatic startup of test target nodes
- Event Handling
  - Top of chapter
  - General
  - Usage
- Dependencies between Test Cases and Suites
  - Top of chapter
  - General
  - Saving configuration data
  - Sequences
- Common Test Hooks
  - Top of chapter
  - General
  - Installing a CTH
  - CTH Scope
  - Manipulating tests
  - Example CTH
  - Built-in CTHs
- Some thoughts about testing
  - Top of chapter
  - Goals
  - What to test?

# 6 Examples and Templates

### 6.1 Test suite example

This example test suite shows some tests of a database server.

    -module(db_data_type_SUITE).

    -include_lib("common_test/include/ct.hrl").

    %% Test server callbacks
    -export([suite/0, all/0,
    	 init_per_suite/1, end_per_suite/1,
    	 init_per_testcase/2, end_per_testcase/2]).

    %% Test cases
    -export([string/1, integer/1]).

    -define(CONNECT_STR, "DSN=sqlserver;UID=alladin;PWD=sesame").

    %%--------------------------------------------------------------------
    %% COMMON TEST CALLBACK FUNCTIONS
    %%--------------------------------------------------------------------

    %%--------------------------------------------------------------------
    %% Function: suite() -> Info
    %%
    %% Info = [tuple()]
    %%   List of key/value pairs.
    %%
    %% Description: Returns list of tuples to set default properties
    %%              for the suite.
    %%--------------------------------------------------------------------
    suite() ->
        [{timetrap,{minutes,1}}].

    %%--------------------------------------------------------------------
    %% Function: init_per_suite(Config0) -> Config1
    %%
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %%
    %% Description: Initialization before the suite.
    %%--------------------------------------------------------------------
    init_per_suite(Config) ->
        {ok, Ref} = db:connect(?CONNECT_STR, []),
        TableName = db_lib:unique_table_name(),
        [{con_ref, Ref },{table_name, TableName}| Config].

    %%--------------------------------------------------------------------
    %% Function: end_per_suite(Config) -> void()
    %%
    %% Config = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %%
    %% Description: Cleanup after the suite.
    %%--------------------------------------------------------------------
    end_per_suite(Config) ->
        Ref = ?config(con_ref, Config),
        db:disconnect(Ref),
        ok.

    %%--------------------------------------------------------------------
    %% Function: init_per_testcase(TestCase, Config0) -> Config1
    %%
    %% TestCase = atom()
    %%   Name of the test case that is about to run.
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %%
    %% Description: Initialization before each test case.
    %%--------------------------------------------------------------------
    init_per_testcase(Case, Config) ->
        Ref = ?config(con_ref, Config),
        TableName = ?config(table_name, Config),
        ok = db:create_table(Ref, TableName, table_type(Case)),
        Config.

    %%--------------------------------------------------------------------
    %% Function: end_per_testcase(TestCase, Config) -> void()
    %%
    %% TestCase = atom()
    %%   Name of the test case that is finished.
    %% Config = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %%
    %% Description: Cleanup after each test case.
    %%--------------------------------------------------------------------
    end_per_testcase(_Case, Config) ->
        Ref = ?config(con_ref, Config),
        TableName = ?config(table_name, Config),
        ok = db:delete_table(Ref, TableName),
        ok.

    %%--------------------------------------------------------------------
    %% Function: all() -> GroupsAndTestCases
    %%
    %% GroupsAndTestCases = [{group,GroupName} | TestCase]
    %% GroupName = atom()
    %%   Name of a test case group.
    %% TestCase = atom()
    %%   Name of a test case.
    %%
    %% Description: Returns the list of groups and test cases that
    %%              are to be executed.
    %%--------------------------------------------------------------------
    all() ->
        [string, integer].

    %%--------------------------------------------------------------------
    %% TEST CASES
    %%--------------------------------------------------------------------

    string(Config) ->
        insert_and_lookup(dummy_key, "Dummy string", Config).

    integer(Config) ->
        insert_and_lookup(dummy_key, 42, Config).

    insert_and_lookup(Key, Value, Config) ->
        Ref = ?config(con_ref, Config),
        TableName = ?config(table_name, Config),
        ok = db:insert(Ref, TableName, Key, Value),
        [Value] = db:lookup(Ref, TableName, Key),
        ok = db:delete(Ref, TableName, Key),
        [] = db:lookup(Ref, TableName, Key),
        ok.

### 6.2 Test suite templates

The Erlang mode for the Emacs editor includes two Common Test test suite templates, one with extensive information in the function headers, and one with minimal information. A test suite template provides a quick start for implementing a suite from scratch and gives you a good overview of the available callback functions. Here are the templates in question:

Large Common Test suite

    %%%-------------------------------------------------------------------
    %%% File    : example_SUITE.erl
    %%% Author  :
    %%% Description :
    %%%
    %%% Created :
    %%%-------------------------------------------------------------------
    -module(example_SUITE).

    %% Note: This directive should only be used in test suites.
    -compile(export_all).

    -include_lib("common_test/include/ct.hrl").

    %%--------------------------------------------------------------------
    %% COMMON TEST CALLBACK FUNCTIONS
    %%--------------------------------------------------------------------

    %%--------------------------------------------------------------------
    %% Function: suite() -> Info
    %%
    %% Info = [tuple()]
    %%   List of key/value pairs.
    %%
    %% Description: Returns list of tuples to set default properties
    %%              for the suite.
    %%
    %% Note: The suite/0 function is only meant to be used to return
    %% default data values, not perform any other operations.
    %%--------------------------------------------------------------------
    suite() ->
        [{timetrap,{minutes,10}}].

    %%--------------------------------------------------------------------
    %% Function: init_per_suite(Config0) ->
    %%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
    %%
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %% Reason = term()
    %%   The reason for skipping the suite.
    %%
    %% Description: Initialization before the suite.
    %%
    %% Note: This function is free to add any key/value pairs to the Config
    %% variable, but should NOT alter/remove any existing entries.
    %%--------------------------------------------------------------------
    init_per_suite(Config) ->
        Config.

    %%--------------------------------------------------------------------
    %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
    %%
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %%
    %% Description: Cleanup after the suite.
    %%--------------------------------------------------------------------
    end_per_suite(_Config) ->
        ok.

    %%--------------------------------------------------------------------
    %% Function: init_per_group(GroupName, Config0) ->
    %%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
    %%
    %% GroupName = atom()
    %%   Name of the test case group that is about to run.
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding configuration data for the group.
    %% Reason = term()
    %%   The reason for skipping all test cases and subgroups in the group.
    %%
    %% Description: Initialization before each test case group.
    %%--------------------------------------------------------------------
    init_per_group(_GroupName, Config) ->
        Config.

    %%--------------------------------------------------------------------
    %% Function: end_per_group(GroupName, Config0) ->
    %%               void() | {save_config,Config1}
    %%
    %% GroupName = atom()
    %%   Name of the test case group that is finished.
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding configuration data for the group.
    %%
    %% Description: Cleanup after each test case group.
    %%--------------------------------------------------------------------
    end_per_group(_GroupName, _Config) ->
        ok.

    %%--------------------------------------------------------------------
    %% Function: init_per_testcase(TestCase, Config0) ->
    %%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
    %%
    %% TestCase = atom()
    %%   Name of the test case that is about to run.
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %% Reason = term()
    %%   The reason for skipping the test case.
    %%
    %% Description: Initialization before each test case.
    %%
    %% Note: This function is free to add any key/value pairs to the Config
    %% variable, but should NOT alter/remove any existing entries.
    %%--------------------------------------------------------------------
    init_per_testcase(_TestCase, Config) ->
        Config.

    %%--------------------------------------------------------------------
    %% Function: end_per_testcase(TestCase, Config0) ->
    %%               void() | {save_config,Config1} | {fail,Reason}
    %%
    %% TestCase = atom()
    %%   Name of the test case that is finished.
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %% Reason = term()
    %%   The reason for failing the test case.
    %%
    %% Description: Cleanup after each test case.
    %%--------------------------------------------------------------------
    end_per_testcase(_TestCase, _Config) ->
        ok.

    %%--------------------------------------------------------------------
    %% Function: groups() -> [Group]
    %%
    %% Group = {GroupName,Properties,GroupsAndTestCases}
    %% GroupName = atom()
    %%   The name of the group.
    %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
    %%   Group properties that may be combined.
    %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
    %% TestCase = atom()
    %%   The name of a test case.
    %% Shuffle = shuffle | {shuffle,Seed}
    %%   To get cases executed in random order.
    %% Seed = {integer(),integer(),integer()}
    %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
    %%              repeat_until_any_ok | repeat_until_any_fail
    %%   To get execution of cases repeated.
    %% N = integer() | forever
    %%
    %% Description: Returns a list of test case group definitions.
    %%--------------------------------------------------------------------
    groups() ->
        [].

    %%--------------------------------------------------------------------
    %% Function: all() -> GroupsAndTestCases | {skip,Reason}
    %%
    %% GroupsAndTestCases = [{group,GroupName} | TestCase]
    %% GroupName = atom()
    %%   Name of a test case group.
    %% TestCase = atom()
    %%   Name of a test case.
    %% Reason = term()
    %%   The reason for skipping all groups and test cases.
    %%
    %% Description: Returns the list of groups and test cases that
    %%              are to be executed.
    %%--------------------------------------------------------------------
    all() ->
        [my_test_case].

    %%--------------------------------------------------------------------
    %% TEST CASES
    %%--------------------------------------------------------------------

    %%--------------------------------------------------------------------
    %% Function: TestCase() -> Info
    %%
    %% Info = [tuple()]
    %%   List of key/value pairs.
    %%
    %% Description: Test case info function - returns list of tuples to set
    %%              properties for the test case.
    %%
    %% Note: This function is only meant to be used to return a list of
    %% values, not perform any other operations.
    %%--------------------------------------------------------------------
    my_test_case() ->
        [].

    %%--------------------------------------------------------------------
    %% Function: TestCase(Config0) ->
    %%               ok | exit() | {skip,Reason} | {comment,Comment} |
    %%               {save_config,Config1} | {skip_and_save,Reason,Config1}
    %%
    %% Config0 = Config1 = [tuple()]
    %%   A list of key/value pairs, holding the test case configuration.
    %% Reason = term()
    %%   The reason for skipping the test case.
    %% Comment = term()
    %%   A comment about the test case that will be printed in the html log.
    %%
    %% Description: Test case function. (The name of it must be specified in
    %%              the all/0 list or in a test case group for the test case
    %%              to be executed).
    %%--------------------------------------------------------------------
    my_test_case(_Config) ->
        ok.

Small Common Test suite

    %%%-------------------------------------------------------------------
    %%% File    : example_SUITE.erl
    %%% Author  :
    %%% Description :
    %%%
    %%% Created :
    %%%-------------------------------------------------------------------
    -module(example_SUITE).

    -compile(export_all).

    -include_lib("common_test/include/ct.hrl").

    %%--------------------------------------------------------------------
    %% Function: suite() -> Info
    %% Info = [tuple()]
    %%--------------------------------------------------------------------
    suite() ->
        [{timetrap,{seconds,30}}].

    %%--------------------------------------------------------------------
    %% Function: init_per_suite(Config0) ->
    %%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
    %% Config0 = Config1 = [tuple()]
    %% Reason = term()
    %%--------------------------------------------------------------------
    init_per_suite(Config) ->
        Config.

    %%--------------------------------------------------------------------
    %% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
    %% Config0 = Config1 = [tuple()]
    %%--------------------------------------------------------------------
    end_per_suite(_Config) ->
        ok.

    %%--------------------------------------------------------------------
    %% Function: init_per_group(GroupName, Config0) ->
    %%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
    %% GroupName = atom()
    %% Config0 = Config1 = [tuple()]
    %% Reason = term()
    %%--------------------------------------------------------------------
    init_per_group(_GroupName, Config) ->
        Config.

    %%--------------------------------------------------------------------
    %% Function: end_per_group(GroupName, Config0) ->
    %%               void() | {save_config,Config1}
    %% GroupName = atom()
    %% Config0 = Config1 = [tuple()]
    %%--------------------------------------------------------------------
    end_per_group(_GroupName, _Config) ->
        ok.

    %%--------------------------------------------------------------------
    %% Function: init_per_testcase(TestCase, Config0) ->
    %%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
    %% TestCase = atom()
    %% Config0 = Config1 = [tuple()]
    %% Reason = term()
    %%--------------------------------------------------------------------
    init_per_testcase(_TestCase, Config) ->
        Config.

    %%--------------------------------------------------------------------
    %% Function: end_per_testcase(TestCase, Config0) ->
    %%               void() | {save_config,Config1} | {fail,Reason}
    %% TestCase = atom()
    %% Config0 = Config1 = [tuple()]
    %% Reason = term()
    %%--------------------------------------------------------------------
    end_per_testcase(_TestCase, _Config) ->
        ok.

    %%--------------------------------------------------------------------
    %% Function: groups() -> [Group]
    %% Group = {GroupName,Properties,GroupsAndTestCases}
    %% GroupName = atom()
    %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}]
    %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase]
    %% TestCase = atom()
    %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}}
    %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail |
    %%              repeat_until_any_ok | repeat_until_any_fail
    %% N = integer() | forever
    %%--------------------------------------------------------------------
    groups() ->
        [].

    %%--------------------------------------------------------------------
    %% Function: all() -> GroupsAndTestCases | {skip,Reason}
    %% GroupsAndTestCases = [{group,GroupName} | TestCase]
    %% GroupName = atom()
    %% TestCase = atom()
    %% Reason = term()
    %%--------------------------------------------------------------------
    all() ->
        [my_test_case].

    %%--------------------------------------------------------------------
    %% Function: TestCase() -> Info
    %% Info = [tuple()]
    %%--------------------------------------------------------------------
    my_test_case() ->
        [].

    %%--------------------------------------------------------------------
    %% Function: TestCase(Config0) ->
    %%               ok | exit() | {skip,Reason} | {comment,Comment} |
    %%               {save_config,Config1} | {skip_and_save,Reason,Config1}
    %% Config0 = Config1 = [tuple()]
    %% Reason = term()
    %% Comment = term()
    %%--------------------------------------------------------------------
    my_test_case(_Config) ->
        ok.