diff options
author | Peter Andersson <[email protected]> | 2011-12-12 14:07:17 +0100 |
---|---|---|
committer | Peter Andersson <[email protected]> | 2011-12-12 14:11:14 +0100 |
commit | fdc50d3b846bdd58524e2c306feda167cea76a2e (patch) | |
tree | af94674d0a333c19977bbf08f9da8367cb68060f | |
parent | d293aac2f300874881ee4148024c63dc644a4104 (diff) | |
parent | e7fc8ebdf5fcf82c581026d7c52e23a53b05ba01 (diff) | |
download | otp-fdc50d3b846bdd58524e2c306feda167cea76a2e.tar.gz otp-fdc50d3b846bdd58524e2c306feda167cea76a2e.tar.bz2 otp-fdc50d3b846bdd58524e2c306feda167cea76a2e.zip |
Merge remote branch 'origin/peppe/common_test/r15b_docs'
* origin/peppe/common_test/r15b_docs:
Update basics chapter and introduce getting started chapter
Document the tc_logfile data
Document new CSS look and the basic_html flag
Document info functions for init/end_per_suite/group
Document the group info function
Document changes in test specifications (groups) and style sheets
Document group specifications in all/0 and the group info function
OTP-9156
-rw-r--r-- | lib/common_test/doc/src/Makefile | 6 | ||||
-rw-r--r-- | lib/common_test/doc/src/basics_chapter.xml | 75 | ||||
-rw-r--r-- | lib/common_test/doc/src/common_test_app.xml | 222 | ||||
-rw-r--r-- | lib/common_test/doc/src/config.gif | bin | 0 -> 4963 bytes | |||
-rw-r--r-- | lib/common_test/doc/src/event_handler_chapter.xml | 10 | ||||
-rw-r--r-- | lib/common_test/doc/src/getting_started_chapter.xml | 230 | ||||
-rw-r--r-- | lib/common_test/doc/src/html_logs.gif | bin | 0 -> 10726 bytes | |||
-rw-r--r-- | lib/common_test/doc/src/part.xml | 1 | ||||
-rw-r--r-- | lib/common_test/doc/src/run_test_chapter.xml | 83 | ||||
-rw-r--r-- | lib/common_test/doc/src/tc_execution.gif | bin | 0 -> 9561 bytes | |||
-rw-r--r-- | lib/common_test/doc/src/write_test_chapter.xml | 121 |
11 files changed, 608 insertions, 140 deletions
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile index 964f7c76c1..d9651f13b0 100644 --- a/lib/common_test/doc/src/Makefile +++ b/lib/common_test/doc/src/Makefile @@ -61,6 +61,7 @@ XML_PART_FILES = part.xml XML_CHAPTER_FILES = \ basics_chapter.xml \ + getting_started_chapter.xml \ install_chapter.xml \ write_test_chapter.xml \ test_structure_chapter.xml \ @@ -80,7 +81,10 @@ MAKE_EDOC = make_edoc BOOK_FILES = book.xml -GIF_FILES = +GIF_FILES = \ + tc_execution.gif \ + config.gif \ + html_logs.gif INSTALL_NOTES = ../../notes.html diff --git a/lib/common_test/doc/src/basics_chapter.xml b/lib/common_test/doc/src/basics_chapter.xml index c1bb365b1f..20141d2561 100644 --- a/lib/common_test/doc/src/basics_chapter.xml +++ b/lib/common_test/doc/src/basics_chapter.xml @@ -28,54 +28,65 @@ <rev></rev> <file>basics_chapter.xml</file> </header> - + <marker id="basics"></marker> <section> <title>Introduction</title> - <p> - The Common Test framework (CT) is a tool which can support - implementation and automated execution of test cases towards different - types of target systems. The framework is based on the OTP Test - Server. Test cases can be run individually or in batches. Common - Test also features a distributed testing mode with central - control and logging. This feature makes it possible to test - multiple systems independently in one common session. This - can be very useful e.g. for running automated large-scale regression - tests. + <p>The <em>Common Test</em> framework (CT) is a tool which supports + implementation and automated execution of test cases towards arbitrary + types of target systems. The CT framework is based on the OTP Test + Server and it's the main tool being used in all testing- and verification + activities that are part of Erlang/OTP system development- and maintenance. + </p> + + <p>Test cases can be executed individually or in batches. Common Test + also features a distributed testing mode with central control and logging + (a feature that makes it possible to test multiple systems independently in + one common session, useful e.g. for running automated large-scale regression + tests). </p> <p> The SUT (System Under Test) may consist of one or several target - nodes. CT contains a generic test server which together with - other test utilities is used to perform test case execution. - It is possible to start the tests from the CT GUI or from an OS- or - Erlang shell prompt. <em>Test suites</em> are files (Erlang + nodes. CT contains a generic test server which, together with + other test utilities, is used to perform test case execution. + It is possible to start the tests from a GUI or from the OS- or + Erlang shell. <em>Test suites</em> are files (Erlang modules) that contain the <em>test cases</em> (Erlang functions) to be executed. <em>Support modules</em> provide functions that the test cases utilize in order to carry out the tests. </p> - <p> - The main idea is that CT based test programs connect to - the target system(s) via standard O&M interfaces. CT - provides implementations and wrappers of some of these O&M - interfaces and will be extended with more interfaces later. - There are a number of target independent interfaces - supported in CT such as Generic Telnet, FTP etc. which can be - specialized or used directly for controlling instruments, - traffic generators etc.</p> + <p>In a black-box testing scenario, CT based test programs connect to + the target system(s) via standard O&M and CLI protocols. CT + provides implementations of, and wrapper interfaces to, some of these + protocols (most of which exist as stand-alone components and + applications in OTP). The wrappers simplify configuration and add + verbosity for logging purposes. CT will be continously extended with + useful support modules. (Note however that it's + a straightforward task to use any arbitrary Erlang/OTP component + for testing purposes with Common Test, without needing a CT wrapper + for it. It's as simple as calling Erlang functions). There + are a number of target independent interfaces supported in CT, such as + Generic Telnet, FTP, etc, which can be specialized or used + directly for controlling instruments, traffic load generators, etc. + </p> <p>Common Test is also a very useful tool for white-box testing Erlang - code since the test programs can call Erlang API functions directly. - For black-box testing Erlang software, Erlang RPC as well as - standard O&M interfaces can be used. + code (e.g. module testing), since the test programs can call exported Erlang + functions directly and there's very little overhead required for + implementing basic test suites and executing simple tests. For black-box + testing Erlang software, Erlang RPC as well as standard O&M interfaces + can for example be used. </p> <p>A test case can handle several connections towards one or several target systems, instruments and traffic generators in parallel in order to perform the necessary actions for a test. The handling of many connections in parallel is one of - the major strengths of Common Test! + the major strengths of Common Test (thanks to the efficient + support for concurrency in the Erlang runtime system - which CT users + can take great advantage of!). </p> </section> @@ -186,7 +197,7 @@ <taglist> <tag>all()</tag> - <item>Returns a list of all test cases in the suite. (Mandatory)</item> + <item>Returns a list of all test cases and groups in the suite. (Mandatory)</item> <tag>suite()</tag> <item>Info function used to return properties for the suite. (Optional)</item> <tag>groups()</tag> @@ -197,12 +208,14 @@ <tag>end_per_suite(Config)</tag> <item>Suite level configuration function, executed after the last test case. (Optional)</item> + <tag>group(GroupName)</tag> + <item>Info function used to return properties for a test case group. (Optional)</item> <tag>init_per_group(GroupName, Config)</tag> <item>Configuration function for a group, executed before the first - test case. (Mandatory if groups are defined)</item> + test case. (Optional)</item> <tag>end_per_group(GroupName, Config)</tag> <item>Configuration function for a group, executed after the last - test case. (Mandatory if groups are defined)</item> + test case. (Optional)</item> <tag>init_per_testcase(TestCase, Config)</tag> <item>Configuration function for a testcase, executed before each test case. (Optional)</item> diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index f58b2ab0a9..c7f6c7ce5c 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -69,12 +69,25 @@ <funcs> <func> - <name>Module:all() -> TestCases | {skip,Reason} </name> - <fsummary>Returns the list of all test cases in the module.</fsummary> + <name>Module:all() -> Tests | {skip,Reason} </name> + <fsummary>Returns the list of all test case groups and test cases + in the module.</fsummary> <type> - <v>TestCases = [atom() | {group,GroupName}]</v> - <v>Reason = term()</v> + <v>Tests = [TestCase | {group,GroupName} | + {group,GroupName,Properties} | + {group,GroupName,Properties,SubGroups}]</v> + <v>TestCase = atom()</v> <v>GroupName = atom()</v> + <v>Properties = [parallel | sequence | Shuffle | {RepeatType,N}] | + default</v> + <v>SubGroups = [{GroupName,Properties} | + {GroupName,Properties,SubGroups}]</v> + <v>Shuffle = shuffle | {shuffle,Seed}</v> + <v>Seed = {integer(),integer(),integer()}</v> + <v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | + repeat_until_any_ok | repeat_until_any_fail</v> + <v>N = integer() | forever</v> + <v>Reason = term()</v> </type> <desc> @@ -85,9 +98,14 @@ This list also specifies the order the cases and groups will be executed by Common Test. A test case is represented by an atom, the name of the test case function. A test case group is - represented by a <c>{group,GroupName}</c> tuple, where - <c>GroupName</c>, an atom, is the name of the group (defined - with <c>groups/0</c>).</p> + represented by a <c>group</c> tuple, where <c>GroupName</c>, + an atom, is the name of the group (defined in <c>groups/0</c>). + Execution properties for groups may also be specified, both + for a top level group and for any of its sub-groups. + Group execution properties specified here, will override + properties in the group definition (see <c>groups/0</c>). + (With value <c>default</c>, the group definition properties + will be used).</p> <p> If <c>{skip,Reason}</c> is returned, all test cases in the module will be skipped, and the <c>Reason</c> will @@ -120,14 +138,16 @@ <desc> <p> OPTIONAL </p> - <p>See <seealso marker="write_test_chapter#test_case_groups">Test case + <p>Function for defining test case groups. Please see + <seealso marker="write_test_chapter#test_case_groups">Test case groups</seealso> in the User's Guide for details.</p> </desc> </func> <func> <name>Module:suite() -> [Info] </name> - <fsummary>Test suite info function (providing default data for the suite).</fsummary> + <fsummary>Test suite info function (providing default data + for the suite).</fsummary> <type> <v> Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | @@ -160,11 +180,11 @@ <p>This is the test suite info function. It is supposed to return a list of tagged tuples that specify various properties - regarding the execution of this test suite (common for all + related to the execution of this test suite (common for all test cases in the suite).</p> <p>The <c>timetrap</c> tag sets the maximum time each - test case is allowed to take (including <c>init_per_testcase/2</c> + test case is allowed to execute (including <c>init_per_testcase/2</c> and <c>end_per_testcase/2</c>). If the timetrap time is exceeded, the test case fails with reason <c>timetrap_timeout</c>. If a <c>TimeFunc</c> function is specified, @@ -172,9 +192,9 @@ <c>TimeVal</c> format.</p> <p>The <c>require</c> tag specifies configuration variables - that are required by test cases in the suite. If the required - configuration variables are not found in any of the - configuration files, all test cases are skipped. For more + that are required by test cases (and/or configuration functions) + in the suite. If the required configuration variables are not found + in any of the configuration files, all test cases are skipped. For more information about the 'require' functionality, see the reference manual for the function <c>ct:require/[1,2]</c>.</p> @@ -196,8 +216,9 @@ </func> <func> - <name>Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | {skip_and_save,Reason,SaveConfig}</name> - <fsummary>Test suite initialization.</fsummary> + <name>Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | + {skip_and_save,Reason,SaveConfig}</name> + <fsummary>Test suite initializations.</fsummary> <type> <v> Config = NewConfig = SaveConfig = [{Key,Value}]</v> <v> Key = atom()</v> @@ -208,15 +229,15 @@ <p> OPTIONAL </p> - <p>This function is called as the first function in the - suite. It typically contains initialization which is common for + <p>This configuration function is called as the first function in the + suite. It typically contains initializations which are common for all test cases in the suite, and which shall only be done - once. The <c>Config</c> parameter is the configuration + once. The <c>Config</c> parameter is the configuration data which can be modified here. Whatever is returned from this function is given as <c>Config</c> to all configuration functions and test cases in the suite. If <c>{skip,Reason}</c> - is returned, all test cases in the suite will be skipped and <c>Reason</c> - printed in the overview log for the suite.</p> + is returned, all test cases in the suite will be skipped + and <c>Reason</c> printed in the overview log for the suite.</p> <p>For information on <c>save_config</c> and <c>skip_and_save</c>, please see <seealso marker="dependencies_chapter#save_config">Dependencies @@ -224,29 +245,106 @@ </desc> </func> - <func> - <name>Module:end_per_suite(Config) -> void() | {save_config,SaveConfig}</name> - <fsummary>Test suite finalization. </fsummary> - <type> - <v> Config = SaveConfig = [{Key,Value}]</v> - <v> Key = atom()</v> - <v> Value = term()</v> - </type> + <func> + <name>Module:end_per_suite(Config) -> void() | + {save_config,SaveConfig}</name> + <fsummary>Test suite finalization. </fsummary> + <type> + <v> Config = SaveConfig = [{Key,Value}]</v> + <v> Key = atom()</v> + <v> Value = term()</v> + </type> + + <desc> + <p> OPTIONAL </p> + <p>This function is called as the last test case in the + suite. It is meant to be used for cleaning up after + <c>init_per_suite/1</c>. + For information on <c>save_config</c>, please see + <seealso marker="dependencies_chapter#save_config">Dependencies + between Test Cases and Suites</seealso> in the User's Guide.</p> + </desc> + </func> + + <func> + <name>Module:group(GroupName) -> [Info] </name> + <fsummary>Test case group info function (providing default data + for a test case group, i.e. its test cases and sub-groups).</fsummary> + <type> + <v> Info = {timetrap,Time} | {require,Required} | + {require,Name,Required} | {userdata,UserData} | + {silent_connections,Conns} | {stylesheet,CSSFile} | + {ct_hooks, CTHs}</v> + <v> Time = TimeVal | TimeFunc</v> + <v> TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | + {hours,integer()}</v> + <v> TimeFunc = {Mod,Func,Args} | Fun</v> + <v> MilliSec = integer()</v> + <v> Mod = atom()</v> + <v> Func = atom()</v> + <v> Args = list()</v> + <v> Fun = fun()</v> + <v> Required = Key | {Key,SubKeys}</v> + <v> Key = atom()</v> + <v> SubKeys = SubKey | [SubKey]</v> + <v> SubKey = atom()</v> + <v> Name = atom()</v> + <v> UserData = term()</v> + <v> Conns = [atom()]</v> + <v> CSSFile = string()</v> + <v> CTHs = [CTHModule | {CTHModule, CTHInitArgs} | + {CTHModule, CTHInitArgs, CTHPriority}]</v> + <v> CTHModule = atom()</v> + <v> CTHInitArgs = term()</v> + </type> <desc> + <p> OPTIONAL </p> - <p>This function is called as the last test case in the - suite. It is meant to be used for cleaning up after <c>init_per_suite/1</c>. - For information on <c>save_config</c>, please see - <seealso marker="dependencies_chapter#save_config">Dependencies between - Test Cases and Suites</seealso> in the User's Guide.</p> - </desc> + <p>This is the test case group info function. It is supposed to + return a list of tagged tuples that specify various properties + related to the execution of a test case group (i.e. its test cases + and sub-groups). Properties set by <c>groups/1</c> override + properties with the same key that have been previously set by + <c>suite/0</c>.</p> + + <p>The <c>timetrap</c> tag sets the maximum time each + test case is allowed to execute (including <c>init_per_testcase/2</c> + and <c>end_per_testcase/2</c>). If the timetrap time is + exceeded, the test case fails with reason + <c>timetrap_timeout</c>. If a <c>TimeFunc</c> function is specified, + it will be called initially and must return a value on + <c>TimeVal</c> format.</p> + + <p>The <c>require</c> tag specifies configuration variables + that are required by test cases (and/or configuration functions) + in the suite. If the required configuration variables are not found + in any of the configuration files, all test cases in this group are skipped. + For more information about the 'require' functionality, see the + reference manual for the function + <c>ct:require/[1,2]</c>.</p> + + <p>With <c>userdata</c>, it is possible for the user to + specify arbitrary test case group related information which can be + read by calling <c>ct:userdata/2</c>.</p> + + <p>The <c>ct_hooks</c> tag specifies which + <seealso marker="ct_hooks_chapter">Common Test Hooks</seealso> + are to be run together with this suite.</p> + + <p>Other tuples than the ones defined will simply be ignored.</p> + + <p>For more information about the test case group info function, + see <seealso marker="write_test_chapter#suite">Test + case group info function</seealso> in the User's Guide.</p> + </desc> </func> <func> - <name>Module:init_per_group(GroupName, Config) -> NewConfig | {skip,Reason}</name> - <fsummary>Test case group initialization.</fsummary> + <name>Module:init_per_group(GroupName, Config) -> NewConfig | + {skip,Reason}</name> + <fsummary>Test case group initializations.</fsummary> <type> <v> GroupName = atom()</v> <v> Config = NewConfig = [{Key,Value}]</v> @@ -258,16 +356,16 @@ <p> OPTIONAL </p> - <p>This function is called before execution of a test case group. - It typically contains initialization which is common for - all test cases in the group, and which shall only be performed - once. <c>GroupName</c> is the name of the group, as specified in - the group definition (see <c>groups/0</c>). The <c>Config</c> - parameter is the configuration which can be modified here. - Whatever is returned from this function is given as <c>Config</c> - to all test cases in the group. If <c>{skip,Reason}</c> is returned, - all test cases in the group will be skipped and <c>Reason</c> printed - in the overview log for the group.</p> + <p>This configuration function is called before execution of a + test case group. It typically contains initializations which are + common for all test cases and sub-groups in the group, and which + shall only be performed once. <c>GroupName</c> is the name of the + group, as specified in the group definition (see <c>groups/0</c>). The + <c>Config</c> parameter is the configuration data which can be modified + here. The return value of this function is given as <c>Config</c> + to all test cases and sub-groups in the group. If <c>{skip,Reason}</c> + is returned, all test cases in the group will be skipped and + <c>Reason</c> printed in the overview log for the group.</p> <p>For information about test case groups, please see <seealso marker="write_test_chapter#test_case_groups">Test case @@ -276,7 +374,8 @@ </func> <func> - <name>Module:end_per_group(GroupName, Config) -> void() | {return_group_result,Status}</name> + <name>Module:end_per_group(GroupName, Config) -> void() | + {return_group_result,Status}</name> <fsummary>Test case group finalization.</fsummary> <type> <v> GroupName = atom()</v> @@ -305,7 +404,7 @@ <func> <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name> - <fsummary>Test case initialization.</fsummary> + <fsummary>Test case initializations.</fsummary> <type> <v> TestCase = atom()</v> <v> Config = NewConfig = [{Key,Value}]</v> @@ -385,10 +484,13 @@ <p>This is the test case info function. It is supposed to return a list of tagged tuples that specify various properties - regarding the execution of this particular test case.</p> + related to the execution of this particular test case. + Properties set by <c>Testcase/0</c> override + properties that have been previously set for the test case + by <c>group/1</c> or <c>suite/0</c>.</p> <p>The <c>timetrap</c> tag sets the maximum time the - test case is allowed to take. If the timetrap time is + test case is allowed to execute. If the timetrap time is exceeded, the test case fails with reason <c>timetrap_timeout</c>. <c>init_per_testcase/2</c> and <c>end_per_testcase/2</c> are included in the @@ -397,16 +499,16 @@ and must return a value on <c>TimeVal</c> format.</p> <p>The <c>require</c> tag specifies configuration variables - that are required by the test case. If the required - configuration variables are not found in any of the + that are required by the test case (and/or <c>init/end_per_testcase/2</c>). + If the required configuration variables are not found in any of the configuration files, the test case is skipped. For more information about the 'require' functionality, see the reference manual for the function <c>ct:require/[1,2]</c>.</p> <p>If <c>timetrap</c> and/or <c>require</c> is not set, the - default values specified in the <c>suite/0</c> return list - will be used.</p> + default values specified by <c>suite/0</c> (or + <c>group/1</c>) will be used.</p> <p>With <c>userdata</c>, it is possible for the user to specify arbitrary test case related information which can be @@ -438,12 +540,12 @@ <p>This is the implementation of a test case. Here you must call the functions you want to test, and do whatever you need to check the result. If something fails, make sure the - function causes a runtime error, or call <c>ct:fail/[0,1]</c> - (which also causes the test case process to crash).</p> + function causes a runtime error, or call <c>ct:fail/1/2</c> + (which also causes the test case process to terminate).</p> - <p>Elements from the <c>Config</c> parameter can be read - with the <c>?config</c> macro. The <c>config</c> - macro is defined in <c>ct.hrl</c></p> + <p>Elements from the <c>Config</c> list can e.g. be read + with <c>proplists:get_value/2</c> (or the macro <c>?config</c> + defined in <c>ct.hrl</c>).</p> <p>You can return <c>{skip,Reason}</c> if you decide not to run the test case after all. <c>Reason</c> will then be diff --git a/lib/common_test/doc/src/config.gif b/lib/common_test/doc/src/config.gif Binary files differnew file mode 100644 index 0000000000..ac8006c4fb --- /dev/null +++ b/lib/common_test/doc/src/config.gif diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml index b41b233ce6..a5886b9687 100644 --- a/lib/common_test/doc/src/event_handler_chapter.xml +++ b/lib/common_test/doc/src/event_handler_chapter.xml @@ -174,6 +174,16 @@ are also given. </p></item> + <item><c>#event{name = tc_logfile, data = {{Suite,Func},LogFileName}}</c> + <p><c>Suite = atom()</c>, name of the test suite.</p> + <p><c>Func = atom()</c>, name of test case or configuration function.</p> + <p><c>LogFileName = string()</c>, full name of test case log file.</p> + <p>This event is sent at the start of each test case (and configuration function + except <c>init/end_per_testcase</c>) and carries information about the + full name (i.e. the file name including the absolute directory path) of + the current test case log file. + </p></item> + <marker id="tc_done"/> <item><c>#event{name = tc_done, data = {Suite,FuncOrGroup,Result}}</c> <p><c>Suite = atom()</c>, name of the suite.</p> diff --git a/lib/common_test/doc/src/getting_started_chapter.xml b/lib/common_test/doc/src/getting_started_chapter.xml new file mode 100644 index 0000000000..7de0912036 --- /dev/null +++ b/lib/common_test/doc/src/getting_started_chapter.xml @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2007</year><year>2010</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Getting Started</title> + <prepared>Peter Andersson</prepared> + <docno></docno> + <date>2011-12-12</date> + <rev></rev> + <file>getting_started_chapter.xml</file> + </header> + + <section> + <title>Are you new around here?</title> + <p> + The purpose of this short chapter is to, with a "learning by example" + approach, give the newcomer a chance to get started quickly writing and + executing some first simple tests. The chapter will introduce some of the + basics, but leave most explanations and details for the later + chapters in this User's Guide. Hopefully though, after this chapter, you + will be inspired and unintimidated enough to go on and get into the + nitty-gritty that follows in this rather heavy User's Guide! If you're + not much into "learning by example" and prefer to get into more technical + detail right away, go ahead and skip to the next chapter. Again, the basics + presented here will be covered in detail in later chapters. + </p> + <p> + This chapter also tries to demonstrate how dead simple it actually is + to write a very basic (yet for many module testing purposes, often sufficiently + complex) test suite, and execute its test cases. This is not necessarily + obvious when you read the rest of the chapters in the User's Guide. + </p> + <p> + A quick note before we start: In order to understand what's discussed and + examplified here, it is recommended that you first read through the + opening <seealso marker="basics_chapter#basics">Common Test Basics</seealso> + chapter. + </p> + </section> + + <section> + <title>Test case execution</title> + <p>Execution of test cases is handled this way:</p> + + <p> + <image file="tc_execution.gif"> + <icaption> + Successful vs unsuccessful test case execution. + </icaption> + </image> + </p> + + <p>For each test case that Common Test is told to execute, it spawns a + dedicated process on which the test case function in question starts + running. (In parallel to the test case process, an idle waiting timer + process is started which is linked to the test case process. If the timer + process runs out of waiting time, it sends an exit signal to terminate + the test case process and this is what's called a <em>timetrap</em>). + </p> + <p>In scenario 1, the test case process terminates normally after case A has + finished executing its test code without detecting any errors. The test + case function simply returns a value and Common Test logs the test case as + successful. + </p> + <p>In scenario 2, an error is detected during test case execution + which causes the test case B function to generate an exception. + This causes the test case process to exit with reason + other than normal, and as a result, Common Test will log this as an + unsuccessful test case. + </p> + <p>As you can understand from the illustration above, Common Test requires + that a test case generates a runtime error to indicate failure (e.g. + by causing a bad match error or by calling <c>exit/1</c>, preferrably + through the <c>ct:fail/1/2</c> help function). A succesful execution is + indicated by means of a normal return from the test case function. + </p> + </section> + + <section> + <title>A simple test suite</title> + <p>As you've seen in the basics chapter, the test suite module implements + callback functions (mandatory or optional) for various purposes, e.g: + <list> + <item>Init/end configuration function for the test suite</item> + <item>Init/end configuration function for a test case</item> + <item>Init/end configuration function for a test case group</item> + <item>Test cases</item> + </list> + The configuration functions are optional and if you don't need them for + your test, a test suite with one simple test case could look like this: + </p> + <pre> + -module(my1st_SUITE). + -compile(export_all). + + all() -> + [mod_exists]. + + mod_exists(_) -> + {module,mymod} = code:load_file(mymod).</pre> + <p> + In this example we check that the <c>mymod</c> module exists (i.e. can be + successfully loaded by the code server). If the operation fails, we will + get a bad match error which terminates the test case. + </p> + </section> + + <section> + <title>A test suite with configuration functions</title> + <p> + If we need to perform configuration operations in order to run our test, we + implement configuration functions in our suite. The result from a + configuration function is configuration data, or simply <em><c>Config</c></em>. + This is a list of key-value tuples which get passed from the configuration + function to the test cases (possibly through configuration functions on + "lower level"). The data flow looks like this: + </p> + + <p> + <image file="config.gif"> + <icaption> + Config data flow in the suite. + </icaption> + </image> + </p> + + <p> + Here's an example of a test suite which uses configuration functions + to open and close a log file for the test cases (an operation that would + be unnecessary and irrelevant to perform by each test case): + </p> + <pre> + -module(check_log_SUITE). + -export([all/0, init_per_suite/1, end_per_suite/1]). + -export([check_restart_result/1, check_no_errors/1]). + + -define(value(Key,Config), proplists:get_value(Key,Config)). + + all() -> [check_restart_result, check_no_errors]. + + init_per_suite(InitConfigData) -> + [{logref,open_log()} | InitConfigData]. + + end_per_suite(ConfigData) -> + close_log(?value(logref, ConfigData)). + + check_restart_result(ConfigData) -> + TestData = read_log(restart, ?value(logref, ConfigData)), + {match,_Line} = search_for("restart successful", TestData). + + check_no_errors(ConfigData) -> + TestData = read_log(all, ?value(logref, ConfigData)), + case search_for("error", TestData) of + {match,Line} -> ct:fail({error_found_in_log,Line}); + nomatch -> ok + end.</pre> + <p> + In this example we have test cases that verify, by parsing a + log file, that our SUT has performed a successful restart and + that no unexpected errors have been printed. + </p> + + <p>To execute the test cases in the test suite above, we could type this on + the Unix/Linux command line (assuming for this example that the suite module + is in the current working directory): + </p> + <pre> + $ ct_run -dir .</pre> + <p>or</p> + <pre> + $ ct_run -suite check_log_SUITE</pre> + + <p>If we want to use the Erlang shell to run our test, we could evaluate this call: + </p> + <pre> + 1> ct:run_test([{dir, "."}]).</pre> + <p>or</p> + <pre> + 1> ct:run_test([{suite, "check_log_SUITE"}]).</pre> + <p> + The result from running our test is printed in log files on HTML format + (stored in unique log directories on different level). This illustration + shows the log file structure: + </p> + + <p> + <image file="html_logs.gif"> + <icaption> + HTML log file structure. + </icaption> + </image> + </p> + </section> + + <section> + <title>What happens next?</title> + <p> + You will find detailed information about the basics introduced here in this + chapter in the following chapters in the User's Guide, as well as + presentations of many more useful features. Have fun! + </p> + </section> +</chapter> + + + + + + + + diff --git a/lib/common_test/doc/src/html_logs.gif b/lib/common_test/doc/src/html_logs.gif Binary files differnew file mode 100644 index 0000000000..3a3fd86bde --- /dev/null +++ b/lib/common_test/doc/src/html_logs.gif diff --git a/lib/common_test/doc/src/part.xml b/lib/common_test/doc/src/part.xml index 3284bcadaa..a74185221d 100644 --- a/lib/common_test/doc/src/part.xml +++ b/lib/common_test/doc/src/part.xml @@ -65,6 +65,7 @@ </description> <xi:include href="basics_chapter.xml"/> + <xi:include href="getting_started_chapter.xml"/> <xi:include href="install_chapter.xml"/> <xi:include href="write_test_chapter.xml"/> <xi:include href="test_structure_chapter.xml"/> diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml index 57059f0ba2..848f278fa6 100644 --- a/lib/common_test/doc/src/run_test_chapter.xml +++ b/lib/common_test/doc/src/run_test_chapter.xml @@ -412,6 +412,16 @@ the way from <c>init_per_suite</c> down to the test cases in the sub group).</p> + <p>With the <c>GroupSpec</c> element (below) it's possible to specify + group execution properties that will override those specified in the + group definition (i.e. in <c>groups/0</c>). Execution properties for + sub-groups may be overridden as well. This feature makes it possible to + change properties of groups at the time of execution, + without even having to edit the test suite. More detailed documentation, + and examples, can be found in the + <seealso marker="write_test_chapter#test_case_groups"> + Test case groups</seealso> chapter.</p> + <p>Below is the test specification syntax. Test specifications can be used to run tests both in a single test host environment and in a distributed Common Test environment (Large Scale @@ -475,8 +485,8 @@ {groups, DirRef, Suite, Groups}. {groups, NodeRefsDirRef, Suite, Groups}. - {groups, DirRef, Suite, Group, {cases,Cases}}. - {groups, NodeRefsDirRef, Suite, Group, {cases,Cases}}. + {groups, DirRef, Suite, GroupSpec, {cases,Cases}}. + {groups, NodeRefsDirRef, Suite, GroupSpec, {cases,Cases}}. {cases, DirRef, Suite, Cases}. {cases, NodeRefs, DirRef, Suite, Cases}. @@ -510,7 +520,8 @@ DirRef = DirAlias | Dir Suites = atom() | [atom()] | all Suite = atom() - Groups = atom() | [atom()] | all + Groups = GroupSpec | [GroupSpec] | all + GroupSpec = Group | {Group,Properties} | {Group,Properties,GroupSpec} Group = atom() Cases = atom() | [atom()] | all Comment = string() | "" @@ -644,14 +655,25 @@ to each individual test case log file for quick viewing with an HTML browser.</p> - <p>The minor log file contain full details of every single test - case, each one in a separate file. This way the files should - be easy to compare with previous test runs, even if the set of - test cases change. If SASL is running those logs will also be - printed there by the + <p>The minor log files contain full details of every single test + case, each one in a separate file. This way, it should be + straightforward to compare the latest results to that of previous + test runs, even if the set of test cases changes. If SASL is running, + its logs will also be printed to the current minor log file by the <seealso marker="common_test:ct_hooks_chapter#builtin_cths"> cth_log_redirect built-in hook</seealso>. - </p> + </p> + + <p>The full name of the minor log file (i.e. the name of the file + including the absolute directory path) can be read during execution + of the test case. It comes as value in the tuple + <c>{tc_logfile,LogFileName}</c> in the <c>Config</c> list (which means it + can also be read by a pre- or post Common Test hook function). Also, + at the start of a test case, this data is sent with an event + to any installed event handler. Please see the + <seealso marker="event_handler_chapter#event_handling">Event Handling</seealso> + chapter for details. + </p> <p>Which information goes where is user configurable via the test server controller. Three threshold values determine what @@ -693,8 +715,15 @@ <section> <marker id="html_stylesheet"></marker> <title>HTML Style Sheets</title> - <p>Common Test includes the <em>optional</em> feature to use - HTML style sheets (CSS) for customizing user printouts. The + <p>Common Test uses a CSS file to control the look of the HTML + files generated during test runs. If, for some reason, the + log files are not displayed correctly in the HTML browser of your + choice, or you prefer the "pre Common Test v1.6 look" + of the log files (i.e. not using CSS), use the start flag/option + <c>basic_html</c> to revert to the old style.</p> + + <p>Common Test includes an <em>optional</em> feature to allow + user HTML style sheets for customizing printouts. The functions in <c>ct</c> that print to a test case HTML log file (<c>log/3</c> and <c>pal/3</c>) accept <c>Category</c> as first argument. With this argument it's possible to @@ -708,22 +737,16 @@ look like this:</p> <pre> -<style> - div.ct_internal { background:lightgrey; color:black } - div.default { background:lightgreen; color:black } - div.sys_config { background:blue; color:white } - div.sys_state { background:yellow; color:black } - div.error { background:red; color:white } -</style> - </pre> + div.sys_config { background:blue; color:white } + div.sys_state { background:yellow; color:black } + div.error { background:red; color:white }</pre> <p>To install the CSS file (Common Test inlines the definition in the HTML code), the name may be provided when executing <c>ct_run</c>. Example:</p> <pre> - $ ct_run -dir $TEST/prog -stylesheet $TEST/styles/test_categories.css - </pre> + $ ct_run -dir $TEST/prog -stylesheet $TEST/styles/test_categories.css</pre> <p>Categories in a CSS file installed with the <c>-stylesheet</c> flag are on a global test level in the sense that they can be used in any @@ -744,8 +767,7 @@ ct:log(sys_state, "Connections: ~p", [ConnectionInfo]), ... ct:pal(error, "Error ~p detected! Info: ~p", [SomeFault,ErrorInfo]), - ct:fail(SomeFault). - </pre> + ct:fail(SomeFault).</pre> <p>If the style sheet is installed as in this example, the categories are private to the suite in question. They can be used by all test cases in the @@ -769,21 +791,6 @@ <p>The <c>Category</c> argument in the example above may have the value (atom) <c>sys_config</c> (white on blue), <c>sys_state</c> (black on yellow) or <c>error</c> (white on red).</p> - - <p>If the <c>Category</c> argument is not specified, Common Test will - use the CSS selector <c>div.default</c> for the - printout. For this reason a user supplied style sheet must - include this selector. Also the selector - <c>div.ct_internal</c> must be included. Hence a minimal - user style sheet should look like this (which is also the - default style sheet Common Test uses if no user CSS file is - provided):</p> - <pre> - <style> - div.ct_internal { background:lightgrey; color:black } - div.default { background:lightgreen; color:black } - </style> - </pre> </section> <section> diff --git a/lib/common_test/doc/src/tc_execution.gif b/lib/common_test/doc/src/tc_execution.gif Binary files differnew file mode 100644 index 0000000000..7c89d7be57 --- /dev/null +++ b/lib/common_test/doc/src/tc_execution.gif diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index e35888e68f..c0ec26ddcc 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -68,7 +68,7 @@ <p>Each test suite module must export the function <c>all/0</c> which returns the list of all test case groups and test cases - in that module. + to be executed in that module. </p> </section> @@ -369,10 +369,12 @@ <title>Test suite info function</title> <p>The <c>suite/0</c> function can be used in a test suite - module to set the default values for the <c>timetrap</c> and - <c>require</c> tags. If a test case info function also specifies - any of these tags, the default value is overruled. See above for - more information. + module to e.g. set a default <c>timetrap</c> value and to + <c>require</c> external configuration data. If a test case-, or + group info function also specifies any of the info tags, it + overrides the default values set by <c>suite/0</c>. See the test + case info function above, and group info function below, for more + details. </p> <p>Other options that may be specified with the suite info list are:</p> @@ -450,11 +452,65 @@ <pre> all() -> [testcase1, {group,group1}, testcase2, {group,group2}].</pre> - <p>Properties may be combined so that e.g. if <c>shuffle</c>, - <c>repeat_until_any_fail</c> and <c>sequence</c> are all specified, the test - cases in the group will be executed repeatedly and in random order until - a test case fails, when execution is immediately stopped and the rest of - the cases skipped.</p> + <p>It is also possible to specify execution properties with a group + tuple in <c>all/0</c>: <c>{group,GroupName,Properties}</c>. These + properties will override those specified in the group definition (see + <c>groups/0</c> above). This way, it's possible to run the same set of tests, + but with different properties, without having to make copies of the group + definition in question.</p> + + <p>If a group contains sub-groups, the execution properties for these may + also be specified in the group tuple: + <c>{group,GroupName,Properties,SubGroups}</c>, where <c>SubGroups</c> + is a list of tuples, <c>{GroupName,Properties}</c>, or + <c>{GroupName,Properties,SubGroups}</c>, representing the sub-groups. + Any sub-groups defined in <c>group/0</c> for a group, that are not specified + in the <c>SubGroups</c> list, will simply execute with their pre-defined + properties.</p> + + <p>Example:</p> + <pre> + groups() -> {tests1, [], [{tests2, [], [t2a,t2b]}, + {tests3, [], [t31,t3b]}]}.</pre> + <p>To execute group 'tests1' twice with different properties for 'tests2' + each time:</p> + <pre> + all() -> + [{group, tests1, default, [{tests2, [parallel]}]}, + {group, tests1, default, [{tests2, [shuffle,{repeat,10}]}]}].</pre> + <p>Note that this is equivalent to this specification:</p> + <pre> + all() -> + [{group, tests1, default, [{tests2, [parallel]}, + {tests3, default}]}, + {group, tests1, default, [{tests2, [shuffle,{repeat,10}]}, + {tests3, default}]}].</pre> + <p>The value <c>default</c> states that the pre-defined properties + should be used.</p> + <p>Here's an example of how to override properties in a scenario + with deeply nested groups:</p> + <pre> + groups() -> + [{tests1, [], [{group, tests2}]}, + {tests2, [], [{group, tests3}]}, + {tests3, [{repeat,2}], [t3a,t3b,t3c]}]. + + all() -> + [{group, tests1, default, + [{tests2, default, + [{tests3, [parallel,{repeat,100}]}]}]}].</pre> + + <p>The syntax described above may also be used in Test Specifications + in order to change properties of groups at the time of execution, + without even having to edit the test suite (please see the + <seealso marker="run_test_chapter#test_specifications">Test + Specifications</seealso> chapter for more info).</p> + + <p>As illustrated above, properties may be combined. If e.g. + <c>shuffle</c>, <c>repeat_until_any_fail</c> and <c>sequence</c> + are all specified, the test cases in the group will be executed + repeatedly, and in random order, until a test case fails. Then + execution is immediately stopped and the rest of the cases skipped.</p> <p>Before execution of a group begins, the configuration function <c>init_per_group(GroupName, Config)</c> is called (the function is @@ -641,6 +697,51 @@ </section> <section> + <marker id="group_info"></marker> + <title>Group info function</title> + + <p>The test case group info function, <c>group(GroupName)</c>, + serves the same purpose as the suite- and test case info + functions previously described in this chapter. The scope for + the group info, however, is all test cases and sub-groups in the + group in question (<c>GroupName</c>).</p> + <p>Example:</p> + <pre> + group(connection_tests) -> + [{require,login_data}, + {timetrap,1000}].</pre> + + <p>The group info properties override those set with the + suite info function, and may in turn be overridden by test + case info properties. Please see the test case info + function above for a list of valid info properties and more + general information.</p> + </section> + + <section> + <title>Info functions for init- and end-configuration</title> + <p>It is possible to use info functions also for the <c>init_per_suite</c>, + <c>end_per_suite</c>, <c>init_per_group</c>, and <c>end_per_group</c> + functions, and it works the same way as with info functions + for test cases (see above). This is useful e.g. for setting + timetraps and requiring external configuration data relevant + only for the configuration function in question (without + affecting properties set for groups and test cases in the suite).</p> + + <p>The info function <c>init/end_per_suite()</c> is called for + <c>init/end_per_suite(Config)</c>, and info function + <c>init/end_per_group(GroupName)</c> is called for + <c>init/end_per_group(GroupName,Config)</c>. Info functions + can not be used with <c>init/end_per_testcase(TestCase, Config)</c>, + however, since these configuration functions execute on the test case process + and will use the same properties as the test case (i.e. the properties + set by the test case info function, <c>TestCase()</c>). Please see the test case + info function above for a list of valid info properties and more + general information. + </p> + </section> + + <section> <marker id="data_priv_dir"></marker> <title>Data and Private Directories</title> |