Back to TTCN-3 Refactoring Catalog
Split Altstep
Altsteps that contain branches which are not closely related to each other are split to maximize reuse potential.
Motivation
Altsteps sometimes contain branches that are not really related to each other, e.g. processing of expected messages paired with generic error handling. To maximize the reuse of branches which are possibly more generic, the altstep should be split into two separate altsteps. The generic parts can then be reused and are not coupled to branches that may be more specific for a certain test case. A typical smell leading to this refactoring is duplicate code, i.e. a number of subsequent branches in various alt statements or altsteps that are equal. The altstep names must be adjusted to reflect the new separate meaning of both altsteps and the unrelated branches in the source altstep must not be mixed in their order. Unlike the Extract Altstep refactoring, the Split Altstep refactoring does not extract any selected branches, but is a real split between two subsequent unrelated sections. As a result, the newly created altstep is not called from a branch within the source altstep, but the behavior calling the source altstep.
Mechanics
- Identify two subsequent semantically unrelated sections of alt branches in the source altstep.
- Create a new target altstep and give it a temporary name. The new altstep should also have the same parameters as specified in the source altstep. If the source altstep runs on a component, the target altstep should run on this component as well.
- Copy one section (source section) to the target altstep.
- Compile.
- Remove the the source section from the source altstep.
- Find all alt statements with calls to the source altstep. Add a new alt branch before or after this call to the source altstep containing a call to the target altstep with the same actual parameters. The position of this new branch depends on the order of the original source altstep: if the branch section moved to the target altstep came first in the source altstep, then a call to the target altstep is inserted before the existing call. Otherwise, it is inserted after the existing call.
- Find all standalone calls to the source altstep. Add a new standalone call statement to the target altstep with the same actual parameters. The position of this statement depends on the order of the original altstep (see previous step).
- Compile and validate.
- Apply the Rename refactoring on both the source and target altstep. The new names should reflect semantics of the separated branches.
- Verify if the parameters of both the source and target altstep are still referenced within the altstep. If there are unused parameters within an altstep signature, apply the Remove Parameter refactoring.
- Compile and validate.
- Apply the Generalize Runs On refactoring on the source and target altstep to exploit further reuse possibilities due to this restructuring.
- Find duplicate branches which are completely equal to either of the split altsteps and replace these branches with their according altstep.
Example
In the next listing, the test case tc_exampleTestCase contains an alt statement which calls the altstep alt_handleExpectedMessages. Within this altstep, there are two different sections: in the first section expected messages are handled and in the second section, there is typical and generic TTCN-3 error handling.
testcase tc_exampleTestCase() runs on ExampleComponent {
timer t_guard;
// [...]
t_guard.start ( 10.0 );
alt {
[] alt_handleExpectedMessage( t_guard ) { }
[] pt.receive( a_expectedMessage ) {
pt.send( a_answerMessage );
}
}
}
altstep alt_handleExpectedMessages( inout timer p_t )
runs on ExampleComponent {
[] pt.receive( a_MessageOne ) {
pt.send( a_MessageTwo );
}
[] pt.receive( a_MessageThree ) {
pt.send( a_MessageFour );
}
[] any port.receive {
setverdict( fail );
stop;
}
[] p_t.timeout {
setverdict( fail );
stop;
}
}
As these two sections are unrelated and the generic error handling can definately be reused, the Split Altstep refactoring is applied. The error handling is now located in the altstep alt_otherwiseFail while the other branches remain in alt_handleExpectedMessages. The altstep alt_otherwiseFail was called from the test case tc_exampleTestCase and was located in the second section of the source altstep. Hence, another alternative branch is inserted after the original call to alt_handleExpectedMessage with a call to alt_otherwiseFail.
As no parameters are necessary anymore in alt_handleExpectedMessages, the parameter p_t was removed by the Remove Parameter refactoring. The Generalize Runs On refactoring caused the removal of the runs on clause in alt_otherwiseFail.
testcase tc_exampleTestCase() runs on ExampleComponent {
timer t_guard;
// [...]
t_guard.start ( 10.0 );
alt {
[] alt_handleExpectedMessage() { }
[] alt_otherwiseFail( t_guard ) { }
[] pt.receive( a_expectedMessage ) {
pt.send( a_answerMessage );
}
}
}
altstep alt_otherwiseFail( inout timer p_t ) {
[] any port.receive {
setverdict( fail );
stop;
}
[] p_t.timeout {
setverdict( fail );
stop;
}
}
altstep alt_handleExpectedMessages()
runs on ExampleComponent {
[] pt.receive( a_MessageOne ) {
pt.send( a_MessageTwo );
}
[] pt.receive( a_MessageThree ) {
pt.send( a_MessageFour );
}
}
