Slicing-based test case generation using UML 2.0 ...

3 downloads 6371 Views 1MB Size Report
strategy derives test cases using slice test coverage, high path coverage and full ... design using slicing of UML interaction diagram' presented at the 2nd.
Int. J. Computational Intelligence Studies, Vol. 3, Nos. 2/3, 2014

Slicing-based test case generation using UML 2.0 sequence diagram Ranjita Kumari Swain* Department of Computer Science, Rourkela Institute of Management Studies, Chhend, Rourkela-769015, Odisha, India E-mail: [email protected] *Corresponding author

Vikas Panthi Department of Computer Science and Engineering, National Institute of Technology, Rourkela-769008, Odisha, India E-mail: [email protected]

Prafulla Kumar Behera Department of Computer Science and Application, Utkal University, Vani Vihar, Bhubaneswar-751007, Odisha, India E-mail: [email protected]

Durga Prasad Mohapatra Department of Computer Science and Engineering, National Institute of Technology, Rourkela-769008, Odisha, India E-mail: [email protected] Abstract: We present a novel test case generation technique using the features of UML 2.0 sequence diagrams. First, we construct the UML sequence diagram of a system. Then, we construct message dependency graph (MDG) from the sequence diagram (SD) and select conditional predicates by traversing MDG. Then, we compute slices corresponding to each conditional predicate. Finally, we generate test cases with respect to a given slicing criterion. Our testing strategy derives test cases using slice test coverage, high path coverage and full predicate coverage criteria. Here, we focus on testing of sequences of messages among objects of use case scenarios. Our technique can be used for system and cluster level testing accommodating the object message and condition information. Thus, our test cases are suitable for detecting object interactions and operational faults. Finally, we have made an analysis and comparison of our approach with the existing approaches, through a case study. Keywords: UML sequence diagram; conditioned slicing; slice test coverage; software testing. Copyright © 2014 Inderscience Enterprises Ltd.

221

222

R.K. Swain et al. Reference to this paper should be made as follows: Swain, R.K., Panthi, V., Behera, P.K. and Mohapatra, D.P. (2014) ‘Slicing-based test case generation using UML 2.0 sequence diagram’, Int. J. Computational Intelligence Studies, Vol. 3, Nos. 2/3, pp.221–250. Biographical notes: Ranjita Kumari Swain completed her MCA from CET, OUAT, Bhubaneswar, India. She is pursuing her PhD degree from Utkal University, Bhubaneswar, India. She is currently working as a Senior Lecturer in Computer Science Department, RIMS, Rourkela, India. She has 12 years of teaching experience. Her fields of interest are software engineering, and discrete mathematics. She has published more than seven papers in the field of software engineering. Vikas Panthi completed his MTech from National Institute of Technology, Rourkela, India. He is pursuing his PhD degree from National Institute of Technology, Rourkela, India. His special fields of interest include software engineering, DBMS, and TOC. He has published more than seven papers in the field of software engineering. Prafulla Kumar Behera has received his PhD degree from Utkal University, Bhubaneswar, India. He is currently working as a reader at Department of Computer Science and Application, in Utkal University, Bhubaneswar, India. His special fields of interest include mobile computing, and software engineering. He is a member of CSI. Durga Prasad Mohapatra received his PhD from IIT, Kharagpur and ME from NIT, Rourkela. He joined the Faculty of the Department of Computer Science and Engineering at National Institute of Technology, Rourkela in 1996, where he is now an Associate Professor. His research interests include software engineering, real-time systems, discrete mathematics and distributed computing. He has published more than 40 research papers in these areas. He has written one book and some book chapters in these areas. He has received many awards including Young Scientist Award for the year 2006 by Orissa Bigyan Academy, Prof. K. Arumugam Award for Innovative Research for the year 2009 and Maharasthra State National Award for Outstanding Research for the year 2010 by ISTE, New Delhi. He has also received three research projects from DST and UGC, Government of India. He is a member of IEEE. This paper is a revised and expanded version of a paper entitled ‘Test case design using slicing of UML interaction diagram’ presented at the 2nd International Conference on Communication, Computing and Security (ICCCS2012), National Institute of Technology, Rourkela, Odisha, India, 6–8 October 2012.

1

Introduction

Testing is a very important part in software development life cycle (SDLC).1 Almost 80% software fail due to improper testing. Generally, testing is performed on code, but if the software can be tested early during SDLC, then maximum errors can be eliminated and we can stop them from propagating to the next stage. So it is required to explore testing possibilities in early stages of SDLC. As the complexity and size of the software increase, the time and effort required to do sufficient testing also increase. Testing is a crucial part

Slicing-based test case generation using UML 2.0 sequence diagram

223

of quality control in the SDLC. One of the most important issues in software testing is test case generation. Test case generation from design specifications has the added advantage of allowing test cases to be available early in the SDLC, thereby making test planning more easier. It is therefore desirable to generate test cases from the software design or analysis documents, in addition to test case design using the code. Both test case design as well as test case executions are time consuming and labour intensive. Hence, automatic test case generation is an important issue. Manual test design is time consuming and error-prone. So, it is necessary to develop automatic test design techniques. With continually increasing software sizes, the issue of automatic design of test cases is getting importance. There are essentially two main approaches to automatic design of test cases. One approach attempts to design test cases from requirement and design specifications and the other one from codes. Test case design from programme code is difficult to automate. Generating test models like flow dependency graph from source code is cumbersome. Most of the requirements and high-level designs of software are documented in the form of models. These models can be used for automatic test case generation of the system (Offutt and Abdurazik, 1999). Generally, large software product is that which can be decomposed into manageable pieces and that an accurate dependency exists among different parts of the software. In this context, programme slicing is a powerful tool that can be used to tackle the problem of size and automatically generate test cases based on the various dependency relations existing among different components. Programme slicing is essentially a decomposition technique that extracts only those programme statements that are relevant to a particular computation (Canfora et al. 1998a). Dynamic slicing considers a particular execution of the programme and hence significantly reduces the size of the computed slice. A dynamic programme slice can be thought of as that part of a programme that affects the computation of a variable of interest during a programme execution on a specific programme input (Korel and Rilling, 1998). A dynamic slice is not larger than and usually smaller than a static slice, because run time information collected during execution is used to compute the slice. The testing effort can be divided into three parts: test case generation, test execution and test evaluation. The latter two parts are relatively easy to be automated provided that the criteria for passing the tests are available. Test cases are generally designed at the specification or code level. Model-driven software development is a relatively new software development paradigm (Dinh-Trong et al., 2006). It has the advantage of increased productivity with support for visualising domains like business and problem domains, solution domain and generation of implementation artefacts. In the model-driven software development, practitioners also use the design model for testing software, especially object-oriented programmes. Design models in object-oriented software testing are used due to three main reasons. They are: 1

traditional software testing techniques consider only static view of code, which is not sufficient for testing dynamic behaviour of object-oriented software (Binder, 1999)

2

use of code to test an object-oriented software is a complex and tedious task, in contrast, models help software testers to understand systems in better way and find test information only after simple processing of models

3

model-based test case generation can be planned at an early stage of the SDLC, allowing software developer to carry out coding and testing in parallel.

224

R.K. Swain et al.

Hence, for these three major reasons, model-based test case generation methodology becomes an obvious choice in software industries and is the focus of our paper. Unified modelling language (UML) consists of different designs that are used to specify both static and dynamic behaviour of the software. UML diagrams are used for modelling object-oriented systems, based on their behaviour. UML is an object management group (OMG) standard for object-oriented modelling that has gain widespread use in the software industry. Using UML, developers model large, complex systems and produce variety of different diagrams presenting different views of the system model. Although UML provides a powerful mechanism for describing software that is safety-critical or that must be highly reliable, very less work has been done in the area of utilising these models for testing purpose (Kundu and Samanta, 2009). With the increasing use of the UML to model object-oriented software, researchers have begun investigating how the UML can be used in the testing phase of the software development process. Consequently, several UML-based approaches to software testing have been proposed (Hartmann et al., 2005; Offutt and Abdurazik, 1999). In these approaches, test requirements and coverage criteria are derived from UML models. Among all diagrams, an interaction diagram can be used to model the collaborating objects in scenarios, showing the objects involved in the scenario and the messages sent and received by them. As a semiformal modelling language, UML is widely used by both academia and industry to describe the analysis and design specifications. Thus, UML models become the sources of test case generation naturally. In this paper, we present an approach for generating test cases at the design level by slicing of UML sequence diagram (SD), as this diagram captures time dependent (temporal) sequences of interactions between objects. There are two kinds of interaction diagrams: SDs and collaboration diagrams. SDs focus on the time sequencing of messages (Utting and Legeard, 2006; Swain et al., 2012a, 2012b, 2012c). Individually or combined together, UML diagrams can be used to perform unit testing as well as integration testing. For example, the state chart diagrams can be used for unit testing and interaction diagrams like collaboration and SDs can be used for integration testing of objects. Typically, the complexity of an object-oriented system lies in its object interactions, not within class methods which tend to be small and simple. As a result, complex behaviours are observed when related objects pass messages with each other within a scenario. We define model-based flow graph to derive control flow information from the UML diagrams. UML provides ways to model the behaviour of an object-oriented system using interaction (sequence and collaboration) diagrams. Because of higher level of abstraction, one of the advantages of model-based flow graph over code-based flow graph is easier extraction of concurrent control flow and dynamic control flow information (such as polymorphism), which will be benefited for testing. Also, UML 2.0 (Ince, 1991) has proposed a set of new features such as interaction and combined fragments which enable designers to model code-like programme structures such as conditions, loops and call to other (SDs). In practice, the interaction (sequence and collaboration) diagrams may be decomposed into several interconnected interaction diagrams. In many cases, an interaction diagram models one nominal scenario and a number of error/exceptional (alternative) scenarios, where the object has to react appropriately. So, interaction diagrams may also be seen as modelling alternative execution sequences of operations belonging to particular scenarios, within the application domain. Complex conditions need to be tested by exercising operation sequences under several alternative conditions.

Slicing-based test case generation using UML 2.0 sequence diagram

225

These alternatives correspond to the different combinations of truth values of predicates in a path realisation condition such that this condition holds true. Various types of faults can arise during integration: interaction faults, message synchronisation faults and dependency faults due to object interactions, etc. Hence, testing each class independently does not eliminate the need for integration testing. We propose a technique for integration testing accommodating the object message and condition information associated with the scenario. In this paper, we propose a test case generation method using UML models. We use SD as a source of test case generation. For generating test data, SD alone may not be enough to decide the different components, i.e., input, expected output and pre- and post-condition of a test case. We propose a message dependency graph (MDG) generated from SDs of use case scenarios, to support control flow analysis of UML 2.0. We traverse the MDG to select the predicates and compute slice2 for each conditional predicate.3 Finally, we generate test data with respect to a given slicing criterion. Our generated test suite aims to cover various interaction faults as well as message sequence faults. These are associated with the object-oriented systems for which the message dependencies and inter- and intra-SDs are considered. Thus, we are able to generate test cases for integration testing and those can also lead to system testing after combining all the test cases of all the scenarios of the system. So, the test cases generated can detect object interaction and message operational faults. We propose a method to generate test cases by slicing of SD. Till now, application of conditioned slicing is used in programme comprehension (Lucia and Fasolino, 1996), debugging and reverse engineering. But, to the best of our knowledge, no work has been reported for testing object-oriented programmes, using conditioned slicing. In this paper, our objective is to achieve adequate test coverage without increasing the number of test cases. Our test case generation technique can be used for system and cluster level testing accommodating the object message and condition information. The test cases thus generated are suitable for detecting synchronisation and messages, object interactions and operational faults. It is possible by slicing the SD on the basis of applying pre-conditions on the messages. In our approach, first we select a conditional predicate on a message during the execution of a SD with a random input data set. Subsequently, we check each path in the MDG by slicing the path and checking the simplicity of the path. The rest of this paper is structured as follows: UML and related diagrams are discussed in Section 2 basic concepts and definitions which are relevant to our technique are described in Section 3. Then, we discuss our methodology for construction of SD and generation of test cases using slicing of SD, in Section 4. In Section 5, we explain the working of our algorithm with an example. Section 6 provides an implementation of our approach with some experimental studies. Section 7 presents the comparison of our work with some related work. Finally, Section 8 concludes this paper.

2

Related UML diagrams

In this section, we have described UML and related UML diagrams used in this paper for test case generation. UML is a language for specifying, visualising, constructing and documenting the artefacts of software systems. UML provides a variety of diagrams that can be used to present different views of an object-oriented system at different stages of

226

R.K. Swain et al.

the development life cycle (OMG, 2004b). UML diagrams can be divided into three broad categories: structural, behavioural and interaction diagrams. The UML structural diagrams are used to model the static aspects of the different elements in the system. These diagrams include class diagram, object diagram, component diagram, package diagram and deployment diagram. Behavioural diagrams focus on the dynamic aspects of the system. These diagrams include use case diagram, activity diagram and state machine diagram. Each specific sequence of interactions in a use case is called a scenario. SDs describe how a set of objects interact with each other to achieve a behavioural goal. Interaction diagrams include SD, communication diagram, timing diagram and interaction overview diagram. Our test generation methodology uses information present in SDs. Prior to UML 2.0, SDs were required to show only a single collaboration. The earlier SDs posed some extra problems: 1

Representing complex control was difficult, i.e., all the variant paths could not be represented.

2

The distinction between a conditional message and a delayed message was weak.

UML 2.0 SDs introduce some extra features to avoid these problems. UML 2.0 also introduces the concept of a combined fragment (OMG, 2004b) to capture complex procedural logic in a SD.

2.1 UML 2.0 SDs The SDs are particularly well-suited for object-oriented software, where they represent the flow of control during object interactions. An UML SD shows a set of interacting objects and the sequence of messages exchanged among them. The diagram may also contain additional information about the flow of control during the interaction, such as conditions and iteration or state-dependent behaviour (OMG, 2004a). The UML 2.0 (OMG, 2004a) syntax of SDs with respect to inter- and intra-SDs is used in this work. Comparing to UML 1.×, UML 2.0 has proposed a set of new features to SDs. Some of the new features are illustrated with an example given in Figure 1. The following interaction operators are used in UML 2.0 SD: alternatives (alt), option (opt), break (break), parallel (par), negative (neg), critical region (region), ignore/consider, assertion (assert), and loop (loop). Below, we briefing explain them. •

Alternatives (alt): It provides various alternatives, out of which only one alternative will be considered. The interaction operands are evaluated on the basis of specified guards. An else guard is provided that evaluates to TRUE if and only if all guards of the other interaction operands evaluate to FALSE.



Option (opt): It defines an optional interactions segment. The model for an opt combined fragment looks like an alt that offers only one interaction.



Break (break): It is the shorthand for an alternative operator where one operand is given and the other assumed to be the rest of the enclosing interaction fragments. In the course of executing an interaction, if the guard of the break is satisfied, then the containing interaction abandons its normal execution and instead performs the clause specified by the break fragment.

Slicing-based test case generation using UML 2.0 sequence diagram

227



Parallel (par): It supports parallel execution of a set of interaction operands.



Loop (loop): It indicates that the interaction operand will be executed repeatedly and also includes a mechanism to stop the iteration.

Figure 1

An UML 2.0 SD showing control flow with fragments (see online version for colours)

In UML 2.0, a message can be one of the following two types: •

Operation call: It expresses the invocation of an operation on the receiving object. An operation call must match the signatures of an operation on the target object (receiver of the message).



Signal: It represents a message object sent out by one object and handled by the other object that is equipped to respond to it.

UML also provides different types of messages. Message sorts identify the sort of communication reflected by a message. The sorts of messages supported are defined in a list called MessageSort. They are •

SynchCall: synchronous call



AsynchCall: asynchronous call



SynchSignal: synchronous signal



AsynchSignal: asynchronous signal.

228

R.K. Swain et al.

UML 2.0 allows SDs to refer to each other through inter-SD control flow using the concept of interaction occurrences.

3

Basic concepts and definitions

In this section, we describe some basic concepts, notations and definitions, which are relevant to our discussion. UML 2.0 allows an element called note, for adding additional information to the SD. Notes are shown with dog-eared rectangle symbols linked to object lifeline through a dashed line. Notes are convenient to include pseudocode, executable statements, constraints, pre-conditions, post-conditions, text annotations, etc. in SD. However, in our approach, we restrict the notes to contain only executable statements. Messages in the SD are chronologically ordered. Definition 1 sequence model: There are two kinds of sequence models: 1

scenarios

2

SDs.

A scenario is a sequence of events which occur during one particular execution of a system. It contains messages between objects and activities performed by objects. Each object transmits information to another object (Blaha and Rumbaugh, 2004). A SD shows the participants in an interaction and the sequence of messages among them. It shows the interaction of a system with its actors to perform all or parts of use cases.

Notations for SD •

Lifeline: Each actor as well as the system is represented by a vertical line called a lifeline as shown in Figure 1. Time proceeds from top to bottom, but the spacing is irrelevant. A lifeline represents the existence of the corresponding object instance at a particular time. Arrows between the lifelines denote communication between object instances using messages. A message can be a request to the receiver object to perform an operation (of the receiver). A synchronous message is shown with a filled arrowhead at the end of a solid line. An asynchronous message is depicted with an open arrowhead at the end of a solid line. Return messages are usually implied. We can explicitly show return messages using an open stick arrowhead with a dashed line as shown in Figure 1. An object is represented by a rectangle drawn at the head of the lifeline.



Activation: An activation (focus of control) shows the period during which an instance is performing a procedure. The procedure being performed may be labelled in text next to the activation symbol or in the margin.

Definition 2 class, cluster and system level testing: Generally testing is done at different levels of abstraction in object-oriented systems: class level, cluster level and system level (Chen et al., 2001; Kim et al., 1999; Smith and Robson, 1992). Class level testing tests the code for each operation supported by a class as well as all possible method interactions within the class. Class level testing also includes testing the methods in each

Slicing-based test case generation using UML 2.0 sequence diagram

229

of the states that a corresponding object may assume. At cluster level testing, the interactions among cooperating classes are tested. This is similar to integration testing. The system level testing is carried out on all the clusters making up the complete system. Definition 3 executable UML: Executable UML can formalise requirements and use cases into a rich set of verifiable diagrams (Mellor and Balcer, 2002; Raistrick et al., 2004). The models are executable and testable and can be translated directly into code by executable UML model compilers. The benefits of this approach go well beyond simply reducing or eliminating the coding stage; it ensures platform independence, avoids obsolescence (programming languages may change, the model does not) and allows full verification of the models by executing them in a test and debug environment. Definition 4 test case: A test case is the triplet (I, T, O) where I is the state of the system at which the test data is input, T is the test data input to the system, and O is the expected output of the system (Andrews et al., 2003; Mall, 2009; Offutt and Abdurazik, 1999). The output produced by the execution of the software with a particular test case provides a specification of the actual software behaviour. Definition 5 slicing criterion: Weiser’s slicing criterion consists of a set of variables of interest and a point of interest within the original programme. Statements which cannot affect the values of variables at a point of interest in the programme are removed to form the slice. In our case, the slicing criterion is (m, V), which specifies the location (identity) of a message m in its corresponding MDG and a set of variables V that is used by the conditional predicate on the message at m. For example in Figure 2, the slicing criterion is (S10, Y). Figure 2

An example showing slice of a programme w.r.t. slicing criterion (S10, Y)

230

R.K. Swain et al.

Definition 6 MDG: We define MDG as a directed graph (V, E), where V is a set of vertices or nodes and E is a set of edges. MDG shows the dependency of a given node on the others. Here, a node represents either a message or a note in the SD and edges represent either control or data dependency among nodes. Here, we have assumed that, notes are attached to objects and the statements on the notes are executed when their corresponding lifelines are activated. The MDG of the given in Figure 2 is shown in Figure 3. MDG does not distinguish between control and data dependence edges. Figure 3

MDG of the programme given in Figure 2

Unstable edge: An outgoing edge (M, Mi) in the dependency graph is said to be unstable edge if there exists an outgoing dependence edge (M, Mj) with Mi not equal to Mj such that the statements Mi and Mj both define the same variable used at M. For example, the edges (M11, M4) and (M11, M8) are unstable edges in Figure 6. The nodes M4, M8 and M11 of the MDG correspond to message4: [b ≤ 30], message8: [b > 120] and message11: (z > 50) respectively in Figure 5. Definition 7 UseVar(x) and AllotVar(x): UseVar(x) is the set of all nodes that use the value of the variable x (Danicic et al., 2004). Here, nodes mean the message points in the SD. For example, in Figure 5, in the expression s = a * b, at message6, there is an use of the value of the variable a. Node number is usually the message timing sequence number in the SD. AllotVar(x) is a set of two types of nodes of MDG, i.e., AllotVar(x) = {P, Q}. Where P is the set of all r nodes that define the variable x. Nodes of type Q are the following: if x is used to specify guards in more than one e node, such e nodes are also treated as members of AllotVar(x). We use the term allotment to indicate that variable x is either defined or is used to specify the guards.

Slicing-based test case generation using UML 2.0 sequence diagram

231

For example, consider nodes M4 and M8 in the MDG shown in Figure 6. These nodes correspond to messages message4: [b ≤ 30] and message8: [b > 120] respectively in Figure 5. For a particular input value, for variable b, only one of these messages will be delivered. Hence, both nodes M4 and M8 of the MDG are treated as members of AllotVar(b). A use of b will require only one of the AllotVar(b), not both. Definition 8 dynamic slice: A dynamic slice of a SD is defined with respect to its corresponding MDG. Consider a predicate on a message m in the MDG of a SD. A dynamic slice is the induced subgraph of MDG, induced by the set of nodes in MDG that affect a predicate at m for a given execution. We call this slice as a dynamic slice of the SD. Those nodes of MDG that do not affect the predicate at m are removed to form the slice, for the slicing criterion (m, V). Definition 9 slice condition, slice domain and boundary: The slice condition of the slice S is the conjunction of all the individual predicates present in the dynamic slice for a given execution. For example, in Figure 5, the slice condition, for the slicing criterion , for the predicate condition, (s < 100), at message6, is the conjunction of [s = a * b, a > 10 and b ≤ 30]. The slice domain of slice S is the set of all input data values for which the slice condition of S is satisfied. A slice domain is surrounded by a boundary. A boundary is a set of data points. A boundary might consist of several segments and each segment of the boundary is called a border (Hajnal and Forgacs, 1993). Each border is determined by a single simple predicate in the slice condition. A border crossing occurs for some input where the conditional predicate changes its Boolean value from true to false or vice versa. Definition 10 conditioned slicing: It forms a bridge between the two extremes of static and dynamic slicing. It was first introduced by Canfora et al. (1998a). Conditioned slicing is a technique for identifying those statements and predicates which contribute to the computation of a selected set of variables when some chosen condition is satisfied (Bertolino and Basanieri, 2000; Danicic et al., 2004; Lucia and Fasolino, 1996). The set of initial states of the programme that characterise these executions is specified in terms of a first order logic formula on the input variables of the programme. Conditioned slices can be identified by using symbolic execution techniques and dependence graphs. In Figure 2, X is the input and the output is the result (Y, Z). Suppose Y and Z are the variables of interest and the programme execution of interest is defined by the condition C = (X > 0, X < 0 and X = 0). The conditioned slice for the criteria (10, C) is only one statement S10, as shown in Figure 2.

3.1 Test adequacy criteria In this subsection, we discuss some test adequacy criteria which are relevant to our approach. Test data adequacy criterion (or coverage criterion) can be used to find out whether a set of test cases is sufficient, or adequate, for testing a given software. Several test coverage criteria such as slice coverage criteria, message path criteria, full predicate coverage, etc. have been proposed in the literature.

232

R.K. Swain et al.



Path coverage criterion: We define path coverage criterion for a SD as follows: consider a test set T and a MDG corresponding to a SD. In order to satisfy the path coverage criterion, it is required that T must cause all dependency paths in a MDG to be taken at least once. A transition coverage does not ensure path coverage.



Message path coverage criterion: This criterion ensures that all the messages between any two objects should appear at least once in an adequate test. Hence, for each message, we have to take account into corresponding test case. A set of concurrent message paths P satisfies all message path criteria if and only if P contains all start to end message paths in the SD. Given a test set T and SD, T must cause each possible message path in SD to be taken at least once. A message path is a sequence of messages and it is a stronger criterion than others.



Slice coverage criterion: We define slice coverage criterion for SD as follows: Given a test set T and SD corresponding to a use case, there must be at least one test case t such that when the software is executed using t, the part that implements the slice of the SD must be executed.



Full predicate coverage criterion: Full predicate coverage requires that each clause should be tested independently (Offutt and Abdurazik, 1999). Given a test set T and SD, T must cause each clause in every predicate on each message in SD to take on the values of TRUE and FALSE while all other clauses in the predicate have values such that the value of the predicate will always be the same as the clause being tested.



Boundary testing criterion: Whenever the test input domain is subdivided into sub domains by decisions (conditional predicates), boundary testing criterion is applicable. Let us consider an arbitrary border for each predicate p. We assume that the conditional predicates on the SD are relational expressions (inequalities). That is, all conditional predicates are of the following form: E1 op E2, where E1 and E2 are arithmetic expressions, and op is one of the operators, =. Jeng and Weyuker (Canfora et al., 1998b) have reported that an inequality border can be adequately tested by using only two points of test input domain, one named ON point and the other named OFF point. The boundary testing criterion is defined (Lucia and Fasolino, 1996) as follows: The boundary testing criterion is satisfied for inequality borders if each selected inequality border b is tested by two points (ON-OFF) of the test input domain such that, if for one of the points the outcome of the predicate p is true, then for the other point the outcome of p is false. Further, the points should be as close as possible to each other and should satisfy all the conditions associated with the border.

3.2 Fault model Every test strategy targets to detect some categories of faults called fault model.

Slicing-based test case generation using UML 2.0 sequence diagram

233



Interaction fault: An interaction fault is an incident of an undesired reaction to an action request, due to violation of a design assumption. In object-oriented programmes, a sequence of messages are exchanged among objects to perform some operation.



Scenario fault: In a SD, each scenario represents a sequence of message paths from starting node to end node. Whenever the sequence of messages do not follow the desired message path due to some situation, then scenario fault is said to be happened.

4

Our test case generation technique

In this section, we present an overview of our proposed approach. Our technique comprises of the following steps and is based on marking and unmarking the intermediate graph. Following are the steps of our approach: Step 1

Construction of the UML SD.

Step 2

Construction of MDG from the SD.

Step 3

Selection of conditional predicates by the traversal of MDG.

Step 4

Transformation of conditional predicates into source code.

Step 5

Computation of slices corresponding to each conditional predicate.

Step 6

Generation of test data with respect to the given slicing criterion.

A schematic representation of our technique is shown in Figure 4.

4.1 Construction of the UML SD A SD also called interaction diagram graphically displays a sequence of messages among the collaborating objects for various scenarios of a use case. A set of such messages forms an interaction. The UML SDs capture time dependent (temporal) sequences of interactions between objects. They show the chronological sequence of the messages, their names and responses and their possible arguments. A SD has two dimensions: the vertical dimension represents time, and the horizontal dimension represents different instances. Normally time proceeds from top to bottom. Message sequence descriptions are provided in SDs to bring forth meanings of the messages passed between objects. SDs describe interactions among software components, and thus are considered to be a good source for cluster level testing. We assume that each SD represents a complete trace of messages during the execution of a user-level operation. We use rational Rose for constructing the UML 2.0 SD.

234 Figure 4

R.K. Swain et al. Schematic representation of our test case generation technique (see online version for colours)

4.2 Construction of MDG from the SD We construct a dependency graph from the SD. We call it as MDG. We construct the MDG statically before execution of the programmes. The MDG is a directed graph which shows the dependency of a given node on the others. If node i is a member of usevar(x) and a node j is a member of defvar(x) then there is a directed edge from node i to node j, also called the dependency edge. Let M be a message in a SD. MDG is a directed graph (V, E), where V is a set of nodes and E is a set of edges. MDG shows the dependency of a given node on the others. Here, a node represents either a message or a note in the SD and edges represent either control or data dependency among nodes. Here, we have assumed that notes are attached to objects and the statements on the notes are executed when its corresponding lifeline is activated. MDG does not distinguish between control or data dependence edges. It does however distinguish between stable and unstable edges. The induced subgraph of MDG of the SD in Figure 5, on the node set (M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14), is shown in Figure 6.

Slicing-based test case generation using UML 2.0 sequence diagram

235

4.3 Selection of conditional predicates by traversing MDG The next step in the test data generation is to select a conditional predicate on the SD. Here, we select predicates in the chronological order of messages. For each conditional predicate, we find the dynamic slice. Testing at the boarders, generates test data for each predicate corresponding to the true or false value of the conditional predicate which also satisfy the slice condition. Here, we perform a traversal on the MDG for selection of predicates. For traversal, we can use any traversal technique like depth first search (DFS) or breadth first search (BFS) to ensure that every message is considered for predicate selection. In this work, we have used a DFS traversal, as with DFS, it becomes easy to keep track of the initial path. This also helps in achieving the message path coverage. During traversal, conditional predicates are looked, on each of the transition.

4.4 Transformation of conditional predicates into source code The predicates are then transformed into predicate functions. Let us consider an initial set of data B0 for the variables that affect a predicate p in the path P of a SD. As already mentioned in our approach, we compute two points named ON and OFF for a given border satisfying the boundary testing criterion. Then, we transform the relational expressions of the predicates to a function F(Predicate function). If the predicate p is of the form (E1 op E2), where E1 and E2 are arithmetic expressions, and op is a relational operator, then F = (E1 – E2) or (E2 – E1) depending on whichever is positive for the data B0. Next, we successively modify the input data B0 such that the function F decreases and finally turns negative. When F turns negative, it corresponds to the alternation of the outcome of the predicate. Hence, as a result of the above predicate transformation, the change in the outcome of predicate p now corresponds to the problem of minimisation of the function F. The basic search procedure we use for finding the minimum of the predicate function F is the alternating variable method (Hajnal and Forgacs, 1993; Korel and Rilling, 1998) which consists of minimising F with respect to each input variable in turn. Each input data variable xi is increased/decreased in steps of Sxi, while keeping all the other data variables constant. Here, Sxi refers to a unit step of the variable xi. For example, the unit step is 1 for integer values. Each predicate in the slice can be considered to be a constraint. If any of the constraint is not satisfied in the slice, for some input data value, we say that a constraint violation has taken place. We compute the value of F when each input data is modified by Sxi. If the function F has decreased on the modified data, and constraint violation has not occurred, then the given data variable and the appropriate direction is selected for minimising F further. We start searching for a minimum with an input variable while keeping all the other input variables constant until the solution is found (the predicate function becomes negative) or the positive minimum of the predicate function is located.

236 Figure 5

R.K. Swain et al. An example of SD with predicate and slicing criteria (see online version for colours)

Slicing-based test case generation using UML 2.0 sequence diagram Figure 6

237

MDG of the SD given in Figure 5

4.5 Computation of slices corresponding to each conditional predicate. In this approach, the slices are generated keeping track of the dependencies from the dependency graph, for all the variables at each message point in the SD. For finding dynamic slices, we use a simple edge marking method. Edge marking methods are reported in Danicic et al. (2004) for generating dynamic slices in the context of procedural programmes. Edge marking algorithm is based on marking and unmarking the edges appropriately as and when dependencies arise and cease at run time. After an execution of node a at run-time, an unstable edge (a, b) is marked, if node a uses the value of the variable defined at node b. A marked unstable edge (a, b) is unmarked after an execution of a node c, if the nodes b and c define the same variable var, and the value of var computed at node b does not affect the present value of var defined at node c (Danicic et al., 204). Let dslice(n) denote the dynamic slice with respect to the most recent execution of the node n (Samuel and Mall, 2008). Let (n, x1), (n, x2), …, (n, xn) be all the marked outgoing dependence edges of n in the updated MDG after an execution of node n. It is clear that the dynamic slice with respect to the present execution of the node n is given by dslice(n) = { x1 , x2 , … , xn } ∪ ⎡⎣ dslice ( x1 ) ∪ dslice ( x2 ) ∪ … ∪ dslice ( xn ) ⎤⎦

(1)

Now, we present a simple edge marking dynamic slicing algorithm for SDs in pseudocode form.

238

R.K. Swain et al.

4.5.1 A simple edge marking slicing algorithm (SEMSAS) for SDs 1

Construct the MDG from SD.

2

Initialise the message sequence: a Unmark all the unstable edges of the MDG. b Set dslice(n) = NULL for every node n of the MDG.

3

For each node n of the message sequence, do the followings: a For every variable used at node n, mark the unstable edge corresponding to its most recent allotment. (Suppose there is a predicate (a > 10) which is true for the given execution step and inputs, then the edge to that predicate is marked. If the predicate is false then it remains unmarked.) b Update dslice(n) using equation (1). c If n is a member of AllotVar(x) and n is not a UseVar(x) node, then do the following: Unmark every marked unstable edge (n1, n2) with n1 ∈ UseVar(x) and n2 is a node that does not affect the present AllotVar(x) of the variable var.

4.6 Generation of test data with respect to the given slicing criterion The dynamic slice (S) will contain the nodes of MDG that actually affect a predicate at run time. From S, we form the slice condition which is the conjunction of all predicates and expressions present in the SD corresponding to the dynamic slice. For each predicate, we generate test data satisfying the slice condition of the computed dynamic slice. For generating test data automatically, we transform the predicates to a predicate function and use function minimisation technique (as discussed in Section 4.4) on it. We generate test data that satisfy all constraints corresponding to a slice. For finding the minimum of the predicate function F, the basic search procedure we use, is the alternating variable method (Hajnal and Forgacs, 1993) which consists of minimising F with respect to each input variable in turn. Consider an initial set of data B0 for the variables that affect a predicate p of a SD. As already mentioned in our approach, based on the generated slice, we compute two points named ON and OFF for a given border satisfying the boundary testing criterion. For this, we transform a predicate p to a function F called a predicate function. If the predicate p is of the form (E1 op E2), where E1 and E2 are arithmetic expressions, and op is a relational operator, then F = (E1 – E2) or (E2 – E1) depending on whichever is positive for the data B0. Next, we successively modify the input data B0 such that the function F decreases and finally turns negative. When F turns negative, it corresponds to the alternation of the outcome of the predicate. Hence, as a result of predicate transformation, the problem of finding the value at which the predicate p changes its Boolean value, corresponds to the minimisation problem of function F. This minimisation can be achieved through repeated modification of input data value. Each input data variable xi is increased/decreased in steps of Uxi, while keeping all the other data variables constant. Here, Uxi refers to a unit step of the variable xi. The unit step depends on the data type being considered. For example, the unit step is 1 for integer values. Each predicate in the slice can be considered to be a constraint. If any of the constraint is not satisfied in the slice, for some

Slicing-based test case generation using UML 2.0 sequence diagram

239

input data value, we say that a constraint violation has taken place. We compute the value of F when each input data is modified by Uxi. If the function F has decreased on the modified data, and constraint violation has not occurred, then the given data variable and the appropriate direction is selected for minimising F further. Here, appropriate direction refers to whether we increase or decrease the data variable xi. We start searching for a minimum with an input variable while keeping all the other input variables constant until the solution is found (the predicate function becomes negative) or the positive minimum of the predicate function is located. Finally, the search continues from this minimum with the next input variable. Figure 7

Algorithm for generating test cases for (s < 100), at message6 of Figure 5 (see online version for colours)

240

R.K. Swain et al.

We present our approach through an algorithm for a particular predicate (s < 100) for the given slicing criterion (6, s) in Figure 7.

5

Working of our approach with an example

Let us consider an example SD as shown in Figure 5. Its corresponding MDG is shown in Figure 6. Let the slicing criterion be (6, s), where 6 means message6 in Figure 5. For this slicing criterion, the slice contains of the set of nodes that corresponds to predicates (a > 10), (b 100) since F(B0) = 200. We should minimise F, in order to alter the Boolean outcome of predicate (s < 100), which is false initially. Hence, we decrease the value of data a in steps. In the first step, we take a = 14, b = 20 and the value of F is calculated as 180 for [a, b] = [14, 20]. Step 1

In the first step, a = 14, b = 20. So s = 14 × 20 = 280 and F = 280 – 100 = 180. So, for [a, b] = [14, 20], the function F = 180. Hence, we observed that F decreases with reduced a.

Step 2

In the next step, the step size is doubled, i.e., the value of a is decreased by 2. Now, [a, b] = [12, 20]. So, F further reduces to F = 240 – 100 = 140.

Step 3

As we double the step size in the next iteration, a becomes a = a – 4 = 12 – 4 = 8, which results in violation of the constraint as (a > 10). Now, s = 8 × 20 = 160. Here, F = 160 – 100 = 60. Again, we increase the step size to 1 and a becomes a = a + 1 = 11. So with [a = 11, b = 20], F = 220 – 100 = 120. But, here as F ≠ 0, the function is not minimised.

Step 4

Then, we select the next variable b and again decrement/increment operation is carried out to reduce F. Here, a remains constant with 10 and b is reduced in steps. So, with [a, b] = [10, 19], F becomes F = 190 – 100 = 90. Then, we repeatedly reduce b as [10, 17], [10, 13], [10, 11], by doubling the step size in each iteration. At last for b = 9, F = 90 – 100 = –10.

Step 5

Since F has turned negative with reduced step size, we take two initial test data points as Bin: [10, 10] which makes F zero and Bout: [11, 9] which makes F negative.

Finally, the generated test cases, for the predicate (s < 100) at message6 are (object1, [11, 9], object2) and (object1, [10, 10], object1) which correspond to different truth values of the predicate (s < 100). Here, the test cases have the form (source object, [test data], target object). Test data has the values of [a, b] for the predicate (s < 100). These generated test cases are satisfying the slice condition of the slice. With this technique, we generate test cases for each such conditional predicates on the SD.

Slicing-based test case generation using UML 2.0 sequence diagram

6

241

An implementation of our approach

This section discusses the results obtained by implementing the proposed approach. The complete approach is implemented using JAVA and Net Beans IDE version 6.0.1. Implementation is done by taking a sample SD as shown in Figure 5 as the case study. We have implemented our approach for generating test cases automatically from UML SD in a prototype tool, named ModelJUnit. We used rational Rose to produce the UML design artefact. Model-based testing allows us to automatically generate test suites from the model of a system under test. ModelJUnit is a Java library that extends JUnit to support model-based testing. It also measures various model coverage metrics. The sender and receiver objects as well as the slice condition are printed along with test cases. In our implementation, we have considered only integer and Boolean variables as part of the conditional expression in SDs. Other data types, however, can easily be considered. Further, for the prototype implementation, we have assumed that the necessary constraints are available in notes instead of class/object diagrams. Extracting data types of attributes, or constraints from class/object diagrams for our implementation can easily be done. The GUI was developed using the Swing component of Java.

6.1 Experimental results In this subsection, we present our experiment to investigate the effectiveness of our generated test cases. Specifically, our experiments are designed to address the following issue. Figure 8

GUI showing the test data with particular input value (a = 25, b = 40, s < 400) (see online version for colours)

242

R.K. Swain et al.

6.1.1 Are the test cases obtained from the proposed approach effective to uncover the faults? In order to answer this issue, we have experimented by taking a number of examples of different application domains and obtained test cases for each of these using our proposed approach. For each application programme, we conducted experiments and generated test cases using the proposed approach. The results are shown in Tables 1 and 2. Table 1 shows the generated test cases. Table 2 shows the achieved path coverage using our experiment. Table 1 Tid

The generated test cases SC

Pr

TC

1

(6, s)

s < 100

{object1, [11, 9], object2}

2

(6, s)

s < 100

{object1, [10, 10], object2}

3

(9, t)

t < 150

{object1, [70, 50], object2}

4

(9, t)

t < 150

{object1, [80, 50], object2}

5

(9, t)

t < 150

{object1, [90, 60], object2}

6

(9, t)

t < 150

{object1, [90, 59], object2}

7

(10, x)

x > 50

{object1, [80, 30], object2}

8

(10, x)

x > 50

{object1, [80, 20], object2}

9

(10, x)

x > 50

{object1, [80, 29], object2}

10

(14, z)

z < 600

{object1, [51, 12], object2}

11

(14, z)

z < 600

{object1, [51, 11], object2}

12

(14, z)

z < 600

{object1, [60, 19], object2}

Notes: Tid: test case ID, SC: slicing criterion, Pr: predicate, TC: test cases.

The generated test cases are also shown in Figure 10. Our tool allows storing the test cases as text files for later processing. The message path coverage and other coverages that are considered while generating the test cases are also displayed along with the test data in Figure 10. Figure 8 shows the UTG display of the set of test cases generated corresponding to our SEMSAS algorithm, of our example. In this figure, the initial state, the final state and the test data corresponding to each predicate are shown. The experimental results show that, on average 96% path coverage can be achieved, using our proposed approach. Table 2 SI. no.

Achieved coverage P

NO

NP

PC

%C

1

ATM

7

28

27

97

2

LIS

8

45

43

96

3

LIS

10

40

40

100

4

VM

8

36

35

98

5

UAS

15

62

60

98

Notes: P: project/application domain, NO: no. of objects, NP: no. of paths, PC: path covered, %C: percentage of path coverage.

Slicing-based test case generation using UML 2.0 sequence diagram

7

243

Comparison with related work

In this section, we focus on the comparison of our work with other UML-based test generation methods. Many researchers (Abdurazik and Offut, 2000; Basanieri et al., 2001; Briand and Labiche, 2002) have been working in the field of software testing for generation of test cases. Most of them use modelling languages to generate test cases. UML is a standardised general-purpose modelling language in the field of software engineering. When test data is generated manually (Abdurazik and Offut, 2000; Basanieri et al., 2001; Briand and Labiche, 2002), the achieved test coverage is usually poor. This is especially true for large systems. For large systems, it is practically impossible to generate test cases by hand that achieve path-based coverage criteria. In the example given in Figure 5, we have shown that the predicate (s