ct_hooks
(common_test)A callback interface on top of Common Test.
The Common Test Hook (CTH) framework allows extensions of the
default behavior of Common Test
by callbacks before and after all
test suite calls. It is intended for advanced users of Common Test
who want to abstract out behavior that is common to multiple test suites.
In brief, CTH allows you to:
Manipulate the runtime configuration before each suite configuration call.
Manipulate the return of all suite configuration calls and by extension the result of the test themselves.
The following sections describe the mandatory and optional CTH
functions that Common Test
calls during test execution.
For more details, see section
Common Test Hooks in the
User's Guide.
For information about how to add a CTH to your suite, see section Installing a CTH in the User's Guide.
Note!
For a minimal example of a CTH, see section Example CTH in the User's Guide.
Callback Functions
The following functions define the callback interface for a CTH.
Functions
Module:init(Id, Opts) -> {ok, State} | {ok, State, Priority}
Id = reference() | term()
Opts = term()
State = term()
Priority = integer()
MANDATORY
This function is always called before any other callback function. Use it to initiate any common state. It is to return a state for this CTH.
Id
is either the return value of
ct_hooks:id/1
,
or a reference
(created using
erlang:make_ref/0
in ERTS) if
ct_hooks:id/1
is not implemented.
Priority
is the relative priority of this hook. Hooks with a
lower priority are executed first. If no priority is specified, it
is set to 0
.
For details about when init
is called, see section
CTH Scope
in the User's Guide.
Module:pre_init_per_suite(SuiteName, InitData, CTHState) -> Result
SuiteName = atom()
InitData = Config | SkipOrFail
Config = NewConfig = [{Key,Value}]
CTHState = NewCTHState = term()
Result = {Return, NewCTHState}
Return = NewConfig | SkipOrFail
SkipOrFail = {fail, Reason} | {skip, Reason}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called before
init_per_suite
if it exists. It typically contains initialization/logging that must
be done before init_per_suite
is called. If
{skip,Reason}
or {fail,Reason}
is returned,
init_per_suite
and all test cases of the suite are skipped
and Reason
printed in the overview log of the suite.
SuiteName
is the name of the suite to be run.
InitData
is the original configuration list of the test
suite, or a SkipOrFail
tuple if a previous CTH has returned
this.
CTHState
is the current internal state of the CTH.
Return
is the result of the init_per_suite
function.
If it is {skip,Reason}
or {fail,Reason}
,
init_per_suite
is never called, instead the initiation is considered to be
skipped or failed, respectively. If a NewConfig
list is
returned,
init_per_suite
is called with that NewConfig
list. For more details, see
section Pre Hooks
in the User's Guide.
This function is called only if the CTH is added before
init_per_suite is run
. For details, see section
CTH Scope
in the User's Guide.
Module:post_init_per_suite(SuiteName, Config, Return, CTHState) -> Result
SuiteName = atom()
Config = [{Key,Value}]
Return = NewReturn = Config | SkipOrFail | term()
SkipOrFail = {fail, Reason} | {skip, Reason} | term()
CTHState = NewCTHState = term()
Result = {NewReturn, NewCTHState}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called after
init_per_suite
if it exists. It typically contains extra checks to ensure that all
the correct dependencies are started correctly.
Return
is what
init_per_suite
returned, that is, {fail,Reason}
, {skip,Reason}
, a
Config
list, or a term describing how
init_per_suite
failed.
NewReturn
is the possibly modified return value of
init_per_suite
.
To recover from a failure in
init_per_suite
,
return ConfigList
with the tc_status
element removed.
For more details, see
Post Hooks in
section "Manipulating Tests" in the User's Guide.
CTHState
is the current internal state of the CTH.
This function is called only if the CTH is added before or in
init_per_suite
. For details, see section
CTH Scope
in the User's Guide.
Module:pre_init_per_group(GroupName, InitData, CTHState) -> Result
GroupName = atom()
InitData = Config | SkipOrFail
Config = NewConfig = [{Key,Value}]
CTHState = NewCTHState = term()
Result = {NewConfig | SkipOrFail, NewCTHState}
SkipOrFail = {fail,Reason} | {skip, Reason}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called before
init_per_group
if it exists. It behaves the same way as
pre_init_per_suite
,
but for function
init_per_group
instead.
Module:post_init_per_group(GroupName, Config, Return, CTHState) -> Result
GroupName = atom()
Config = [{Key,Value}]
Return = NewReturn = Config | SkipOrFail | term()
SkipOrFail = {fail,Reason} | {skip, Reason}
CTHState = NewCTHState = term()
Result = {NewReturn, NewCTHState}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called after
init_per_group
if it exists. It behaves the same way as
post_init_per_suite
,
but for function
init_per_group
instead.
Module:pre_init_per_testcase(TestcaseName, InitData, CTHState) -> Result
TestcaseName = atom()
InitData = Config | SkipOrFail
Config = NewConfig = [{Key,Value}]
CTHState = NewCTHState = term()
Result = {NewConfig | SkipOrFail, NewCTHState}
SkipOrFail = {fail,Reason} | {skip, Reason}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called before
init_per_testcase
if it exists. It behaves the same way as
pre_init_per_suite
,
but for function
init_per_testcase
instead.
CTHs cannot be added here right now. That feature may be added in a later release, but it would right now break backwards compatibility.
Module:post_init_per_testcase(TestcaseName, Config, Return, CTHState) -> Result
TestcaseName = atom()
Config = [{Key,Value}]
Return = NewReturn = Config | SkipOrFail | term()
SkipOrFail = {fail,Reason} | {skip, Reason}
CTHState = NewCTHState = term()
Result = {NewReturn, NewCTHState}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called after
init_per_testcase
if it exists. It behaves the same way as
post_init_per_suite
,
but for function
init_per_testcase
instead.
Module:pre_end_per_testcase(TestcaseName, InitData, CTHState) -> Result
TestcaseName = atom()
InitData = Config
Config = NewConfig = [{Key,Value}]
CTHState = NewCTHState = term()
Result = {NewConfig, NewCTHState}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called before
end_per_testcase
if it exists. It behaves the same way as
pre_end_per_suite
,
but for function
end_per_testcase
instead.
This function can not change the result of the test case by returning skip or fail
tuples, but it may insert items in Config
that can be read in
end_per_testcase/2
or in post_end_per_testcase/4
.
Module:post_end_per_testcase(TestcaseName, Config, Return, CTHState) -> Result
TestcaseName = atom()
Config = [{Key,Value}]
Return = NewReturn = Config | SkipOrFail | term()
SkipOrFail = {fail,Reason} | {skip, Reason}
CTHState = NewCTHState = term()
Result = {NewReturn, NewCTHState}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called after
end_per_testcase
if it exists. It behaves the same way as
post_end_per_suite
,
but for function
end_per_testcase
instead.
Module:pre_end_per_group(GroupName, EndData, CTHState) -> Result
GroupName = atom()
EndData = Config | SkipOrFail
Config = NewConfig = [{Key,Value}]
CTHState = NewCTHState = term()
Result = {NewConfig | SkipOrFail, NewCTHState}
SkipOrFail = {fail,Reason} | {skip, Reason}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called before
end_per_group
if it exists. It behaves the same way as
pre_init_per_suite
,
but for function
end_per_group
instead.
Module:post_end_per_group(GroupName, Config, Return, CTHState) -> Result
GroupName = atom()
Config = [{Key,Value}]
Return = NewReturn = Config | SkipOrFail | term()
SkipOrFail = {fail,Reason} | {skip, Reason}
CTHState = NewCTHState = term()
Result = {NewReturn, NewCTHState}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called after
end_per_group
if it exists. It behaves the same way as
post_init_per_suite
,
but for function
end_per_group
instead.
Module:pre_end_per_suite(SuiteName, EndData, CTHState) -> Result
SuiteName = atom()
EndData = Config | SkipOrFail
Config = NewConfig = [{Key,Value}]
CTHState = NewCTHState = term()
Result = {NewConfig | SkipOrFail, NewCTHState}
SkipOrFail = {fail,Reason} | {skip, Reason}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called before
end_per_suite
if it exists. It behaves the same way as
pre_init_per_suite
,
but for function
end_per_suite
instead.
Module:post_end_per_suite(SuiteName, Config, Return, CTHState) -> Result
SuiteName = atom()
Config = [{Key,Value}]
Return = NewReturn = Config | SkipOrFail | term()
SkipOrFail = {fail,Reason} | {skip, Reason}
CTHState = NewCTHState = term()
Result = {NewReturn, NewCTHState}
Key = atom()
Value = term()
Reason = term()
OPTIONAL
This function is called after
end_per_suite
if it exists. It behaves the same way as
post_init_per_suite
,
but for function
end_per_suite
instead.
Module:on_tc_fail(TestName, Reason, CTHState) -> NewCTHState
TestName = init_per_suite | end_per_suite | {init_per_group,GroupName} | {end_per_group,GroupName} | {FuncName,GroupName} | FuncName
FuncName = atom()
GroupName = atom()
Reason = term()
CTHState = NewCTHState = term()
OPTIONAL
This function is called whenever a test case (or configuration function) fails. It is called after the post function is called for the failed test case, that is:
If
init_per_suite
fails, this function is called afterpost_init_per_suite
.If a test case fails, this funcion is called after
post_end_per_testcase
.
If the failed test case belongs to a test case group, the first
argument is a tuple {FuncName,GroupName}
, otherwise only
the function name.
The data that comes with Reason
follows the same format as
FailReason
in event
tc_done
.
For details, see section
Event Handling
in the User's Guide.
Module:on_tc_skip(TestName, Reason, CTHState) -> NewCTHState
TestName = init_per_suite | end_per_suite | {init_per_group,GroupName} | {end_per_group,GroupName} | {FuncName,GroupName} | FuncName
FuncName = atom()
GroupName = atom()
Reason = {tc_auto_skip | tc_user_skip, term()}
CTHState = NewCTHState = term()
OPTIONAL
This function is called whenever a test case (or configuration function) is skipped. It is called after the post function is called for the skipped test case, that is:
If
init_per_group
is skipped, this function is called afterpost_init_per_group
.If a test case is skipped, this function is called after
post_end_per_testcase
.
If the skipped test case belongs to a test case group, the first
argument is a tuple {FuncName,GroupName}
, otherwise only
the function name.
The data that comes with Reason
follows the same format as
events
tc_auto_skip
and
tc_user_skip
For details, see section
Event Handling
in the User's Guide.
Module:terminate(CTHState)
CTHState = term()
OPTIONAL
This function is called at the end of a CTH scope.
Module:id(Opts) -> Id
Opts = term()
Id = term()
OPTIONAL
The Id
identifies a CTH instance uniquely. If two CTHs return
the same Id
, the second CTH is ignored and subsequent calls to
the CTH are only made to the first instance. For details, see section
Installing a CTH
in the User's Guide.
This function is not to have any side effects, as it can
be called multiple times by Common Test
.
If not implemented, the CTH acts as if this function returned a call
to make_ref/0
.