Erlang -- Examples and Templates

Common Test

User's Guide

Version 1.17

- User's Guide
- Reference Manual
- Release Notes
- PDF
- Top

- Expand All
- Contract All

### Chapters

- Introduction
  - Top of chapter
  - Scope
  - Prerequisites
- Common Test Basics
  - Top of chapter
  - General
  - Test Suite Organisation
  - Support Libraries
  - Suites and Test Cases
  - External Interfaces
- Getting Started
  - Top of chapter
  - Introduction for Newcomers
  - Test Case Execution
  - A Simple Test Suite
  - A Test Suite with Configuration Functions
  - Questions and Answers
- 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 Information Function
  - Test Suite Information Function
  - Test Case Groups
  - Parallel Property and Nested Groups
  - Parallel Test Cases and I/O
  - Repeated Groups
  - Shuffled Test Case Order
  - Group Information Function
  - Information Functions for Init- and End-Configuration
  - Data and Private Directories
  - Execution Environment
  - Timetrap Time-Outs
  - Logging - Categories and Verbosity Levels
  - Illegal Dependencies
- Test Structure
  - Top of chapter
  - General
  - Skipping Test Cases
  - Definition of Terms
- Examples and Templates
  - Top of chapter
  - Test Suite Example
  - Test Suite Templates
- Running Tests and Analyzing Results
  - 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 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
  - Use
  - 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
  - Use
  - Test Specifications
  - Automatic Startup of Test Target Nodes
- Event Handling
  - Top of chapter
  - General
  - Use
- 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
  - Synchronizing External User Applications with Common Test
  - Example CTH
  - Built-In CTHs
- Some Thoughts about Testing
  - Top of chapter
  - Goals
  - What to Test

# 7 Examples and Templates

### 7.1 Test Suite Example

The following 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) -> term()
     %%
     %% 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) -> term()
     %%
     %% 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.

### 7.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 a good overview of the available callback functions. The two templates follows:

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) -> term() | {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) ->
     %%               term() | {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) ->
     %%               term() | {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) -> term() | {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) ->
     %%               term() | {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) ->
     %%               term() | {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.