Patterns: From System Design To Software Testing: Jason O. Hallstrom Adem Delibas
Patterns: From System Design To Software Testing: Jason O. Hallstrom Adem Delibas
Patterns: From System Design To Software Testing: Jason O. Hallstrom Adem Delibas
DOI 10.1007/s11334-007-0042-z
ORIGINAL PAPER
Received: 16 December 2007 / Accepted: 19 December 2007 / Published online: 12 January 2008
© Springer-Verlag London Limited 2008
Abstract Design patterns are used extensively in the design of the particular system by specifying a set of specializa-
of software systems. Patterns codify effective solutions for tion rules that are designed to reflect the scenarios in which
recurring design problems and allow software engineers to the defects codified in this set of PTCTs are likely to man-
reuse these solutions, tailoring them appropriately to their ifest themselves in the particular system. We illustrate the
particular applications, rather than reinventing them from approach using the Observer pattern.
scratch. In this paper, we consider the following question:
How can system designers and implementers test whether Keywords Design patterns · Contracts · Testing
their systems, as implemented, are faithful to the require-
ments of the patterns used in their design? A key considera- 1 Introduction
tion underlying our work is that the testing approach should
enable us, in testing whether a particular pattern P has been Design patterns [4,11,24] have had a profound impact on
correctly implemented in different systems designed using how software systems are built. This is not surprising since
P, to reuse the common parts of this effort rather than hav- patterns capture the distilled wisdom of the software com-
ing to do it from scratch for each system. Thus in the approach munity, and provide effective solutions to recurring design
we present, corresponding to each pattern P, there is a set problems. They allow software engineers to reuse these solu-
of pattern test case templates (PTCTs). A PTCT codifies a tions, tailoring them to the needs of their particular systems,
reusable test case structure designed to identify defects asso- rather than reinventing them from scratch. Patterns are used
ciated with applications of P in all systems designed using primarily during the design phase of software systems. In
P. Next we present a process using which, given a system this paper, we focus on later stages of the software life-cycle,
designed using P, the system tester can generate a test suite the testing and maintenance phases. Specifically, the ques-
from the PTCTs for P that can be used to test the particular tion we are interested in is, how can system designers and
system for bugs in the implementation of P in that system. implementers test whether their systems, as implemented, are
This allows the tester to tailor the PTCTs for P to the needs faithful to the requirements of the underlying patterns? This
question is especially important for large systems since such
N. Soundarajan (B) · G. Shu · A. Delibas
Computer Science and Engineering, Ohio State University,
systems tend to have correspondingly large software teams
Columbus, OH 43210, USA and hence a correspondingly greater likelihood that differ-
e-mail: neelam@cse.ohio-state.edu ent members of the team may have subtly different inter-
G. Shu pretations of the patterns underlying the system’s design.
e-mail: shug@cse.ohio-state.edu Hence the team members may implement their respective
A. Delibas parts of the system in ways such that when these parts are put
e-mail: delibas@cse.ohio-state.edu together, the resulting overall system is not compatible with
the patterns’ intent. Design-related bugs of this kind may not
J. O. Hallstrom
School of Computing, Clemson University,
manifest themselves in test cases that are developed using
Clemson, SC 29634, USA standard approaches such as testing against the functional
e-mail: jasonoh@cs.clemson.edu requirements or even code-based criteria such as statement,
123
72 N. Soundarajan et al.
or branch, or path coverage [3]. The testing techniques and only create the subcontract that specifies how the pattern is
supporting tools discussed in this paper will be of value in specialized for use in a particular application.
reducing the likelihood of such bugs going undetected, and A similar consideration is a primary motivation for the
will aid in their localization. approach we present in this paper. That is, a key goal of our
The problem of ensuring that a system is faithful to the work is that the testing approach should enable us, in test-
patterns underlying its design is even more serious during ing whether a particular pattern P has been correctly imple-
the maintenance phase since system maintenance may be mented in different systems designed using P, to reuse the
the responsibility of team members who were not involved common parts of this effort rather than having to implement it
with the original design or implementation of the system— from scratch for each of these systems. Thus in the approach
and consequently have only a superficial understanding of we develop, corresponding to each pattern P, there is a set
its design. As a result, over time, the design integrity of the of what we will call pattern test case templates (PTCTs). A
system is likely to erode. The approach we develop in this PTCT codifies a reusable test case structure designed to iden-
paper can help address this aspect of the problem as well. tify defects associated with applications of P in all systems
This is because the test suite used to test whether the system designed using P. Next we present a process using which,
is faithful to its underlying patterns can be included as a given any system designed using P, the system tester can
key part of the system’s design documentation in the same generate a test suite from the PTCTs for P that can be used
manner as standard unit tests or other functionality tests. As to test the particular system for bugs in the implementation
the system evolves during maintenance, the design test suite of P. The process allows the system tester to tailor the set
will help system maintainers identify and localize changes of PTCTs corresponding to P to the needs of the particular
that may conflict with the original design. If one of these tests system by specifying a set of specialization rules that are
were to fail, that doesn’t necessarily mean that the changes designed to reflect the structure and the scenarios in which
in question are flawed. It may be that the design needs to the defects codified in the set of PTCTs for P are likely to
be modified; but this decision should be made consciously manifest themselves.
with the design documentation being appropriately updated, An example will help illustrate our approach. Consider
rather than simply modifying the code. We will return to this the classic Observer pattern which we will use as our pri-
point in the final section of the paper. mary case study throughout the paper. According to the stan-
In standard software testing, we test software against its dard description [4,11] of the pattern, participating objects
specifications. These specifications must be formal since, play one of two roles: Subject or Observer. The intent of
otherwise, there is no way to conclude whether a test was suc- the pattern is to keep multiple observers consistent with
cessful or not1 . Similarly, to test whether a system is faithful the state of a single subject. When an object wishes to
to the intent of the patterns underlying its design, we need become an observer of a subject, it invokes the subject’s
formal specifications of the patterns. Attach() method. When it is no longer interested, it invokes
In previous work [12,26,31], we presented an approach to the Detach() method. In addition, Subject includes a
providing precise specifications for patterns and their appli- Notify() method which, according to the intended usage of
cations in the form of pattern contracts and subcontracts. It the pattern, is required to be called whenever the state of the
is against these contracts and subcontracts that we wish to subject is modified. Notify() is required to invoke Update()
test individual systems to validate their design correctness. on each attached observer which must, in turn, update the
An important aspect of this approach to pattern speci- state of that observer to make it consistent2 with the current
fication is that the requirements and behavioral guarantees subject state.
specified in a pattern contract apply to all uses of the pattern; The standard UML diagram for the pattern appears in
a subcontract characterizes how the pattern is specialized in Fig. 1. The subject maintains a set of references to the
a particular application. Thus the wisdom of the community currently attached observers in the variable _observers.
captured in a design pattern is reflected in the corresponding According to the standard description, when Attach() is
pattern contract; it can be reused by every team that uses the invoked, it adds a reference to the attaching observer to
pattern in the design of its system. The individual team need _observers. But if this was all Attach() did, the intent of the
pattern would be violated; this is because the newly attached
observer’s state may not be consistent with the current state
1 When is a test successful? One definition in the testing literature [3] of the subject – it will remain inconsistent until the next
says that a test is successful when it shows that the software does not
meet its specification, since the purpose of the test is to find flaws in
the software. Others [20] use the convention that a test succeeds, or that 2 What precisely terms such as “modified” and “consistent” mean is not
the software “passes” the test if, during the test execution, the software clear from such informal descriptions. The formal contract for Observer
behaves according to its specification. We will use this latter convention which we will see in the next section will resolve this and other ambi-
in this paper. guities in the informal description.
123
Patterns: from system design to software testing 73
2 Pattern contracts
Fig. 1 Observer pattern
123
74 N. Soundarajan et al.
123
Patterns: from system design to software testing 75
(a reference to) this object will be in players[0]. The rest in a particular application, that s1, s2 are two states of the
of the objects in players[] will be the objects that enroll to subject, and o1 is the state of an observer. Suppose that the
play the Observer role (by invoking the Attach() method, definitions of Modified() and Consistent() for this application
this being the action required for this purpose as specified are such that each of the following is true:
in the (elided from Fig. 2) enrollment clause for this role). Consistent (s1,o1), ¬Modified (s1,s2), and
Thus the invariant (lines 10–11) states that the state of the ¬Consistent (s2,o1)
first object in players[], i.e., the state of the subject in any
Suppose, at some point in the execution of this system, the
given instance of this pattern, is Consistent() with the states
subject is in the state s1 and the observer in the state o1.
of each of the observers (currently) enrolled in this instance.
Suppose, finally, that the subject state changes from s1 to
Next we have (part of) the Subject role contract. First we
s2. Then, according to the others specification in the Sub-
specify the state of the subject as consisting of obs, used to
ject role, the Notify() method will not be invoked and hence
store references to the currently attached observers. Next we
Update() will not be invoked on this observer and its state
have the specification of Attach(), one of the named methods
would remain as o1. At this point, the current state, o1, of the
of this role. The pre-condition requires that the attaching
observer will be inconsistent with the current state, s2, of
observer not already be attached, i.e., not have a reference
the subject, and the invariant that the pattern was intended
to it in obs. The post-condition states4 that a reference to the
to guarantee will be violated although the individual meth-
object is added to obs; that the subject itself is not modified,
ods in the individual roles, as actually implemented in the
in the sense of the auxiliary concept Modified(), and that one
particular application, satisfy their respective specifications.
call to a named method of the pattern has been made during
The problem is that we have conflicting notions of what a
the execution of Attach(), this being to the Update() method
sufficiently serious modification in the subject state is that
invoked on the attaching observer.
requires the observers to be updated on the one hand, versus
The others specification (lines 20–23) states that any
what it means for the subject state to be consistent with the
other method of the class playing the Subject role should
observer state, on the other. The constraint specified (lines
make no change in obs, and should either not modify (again
6–8) in the contract ensures that this problem doesn’t arise.
in the sense of Modified()) the subject state, or must invoke
Thus while the designers of a particular system are free to
the Notify() method (on the current subject). The (elided)
tailor the definitions of the auxiliary concepts to their partic-
specification of Notify() states that this method invokes
ular needs, they must ensure that these definitions satisfy the
Update() on each observer in obs.
constraint specified in the contract.
The Observer role contract states that the state of this
How realistic is this problem? That is, how likely is it
role consists of the variable sub (that holds a reference to
that the software team responsible for an actual application
the subject to which this observer is attached); that the
designed using the Observer pattern would base their sys-
Update() method does not change the value of sub, and
tem on such mutually conflicting notions of Modified() and
makes the state of the observer to be consistent (in the sense
Consistent()? It depends on the size of the team in question;
of the auxiliary concept Consistent()) with that of the sub-
as the team grows larger, the likelihood of such problems
ject. The others specification also states that it not modify
seem to also grow. But even for relatively small systems, the
sub, and leave the observer in a state that is consistent with
problem can creep in during system evolution; we will see
that of the subject5 .
an example of this later in the paper.
Let us now consider the constraint specified in the con-
Unfortunately, however, specific PTCTs (or, more pre-
tract (lines 6–8). Although the definitions of the auxiliary
cisely, test cases obtained by specializing them for a partic-
concepts, tailored to the needs of a particular application, will
ular application) cannot test these constraints because they
be provided by the corresponding subcontract, these defini-
are general conditions typically involving universal quanti-
tions cannot be completely arbitrary. For example, suppose,
fiers over the states of the various objects enrolled in the
pattern instance. Instead, violations of these constraints may
4 We use the “#” notation in the post-condition to refer to the pre- show up as violations of, for example, the pattern invariant—
condition value of the variable, i.e., its value when the method started although the individual methods invoked as part of the test
execution. case may satisfy their own specifications. We will see this in
5 Standard informal descriptions [11,25] of the pattern seem to suggest
the discussion of the example.
that the other methods of this role should not make any changes in
the state of the observer. But this is unnecessarily restrictive. As the
pattern contract states, all we need is that any changes in the observer 3 Pattern test case templates (PTCTs)
be such that they leave the observer state consistent with the sub-
ject state. This is an example [12,26] of how our pattern contracts can
identify dimensions of flexibility that may be missing in the standard Given the requirements captured in a pattern contract, how
informal descriptions. do we develop appropriate PTCTs that can be used to test
123
76 N. Soundarajan et al.
123
Patterns: from system design to software testing 77
123
78 N. Soundarajan et al.
123
Patterns: from system design to software testing 79
123
80 N. Soundarajan et al.
123
Patterns: from system design to software testing 81
123
82 N. Soundarajan et al.
123
Patterns: from system design to software testing 83
Unfortunately, however, the test cases generated using the can the work described here be new? The standard meaning of
PTCTs we have seen will not catch this error. The problem testing pattern refers to a pattern used to address a recurring
is that, according to the definition of the auxiliary concepts problem in the context of software testing. Indeed, a test(ing)
in Fig. 6, if only the value of _medLvl changes, the state pattern is simply a special type of design pattern [17], one
of the patient is not considered to be modified; moreover, intended to guide the design of testing code. Our work, how-
the state of nurse is considered to be consistent with that ever, is focused on validating the correct usage of design
of the patient as long as the former has the correct infor- patterns through software testing. We note that other authors
mation about the value of the _temp of the latter. Thus any have also considered applying design patterns as part of the
test cases generated from the PTCT in Fig. 5 will succeed system design process to improve testability [1,6]. Again,
when executed. If we were to change the definition of one however, our focus has been on ensuring the correct applica-
of these concepts but not the other, the constraint specified tion of patterns.
in the original pattern contract (lines 6–8 of Fig. 2) will be It is important to note that McGregor [17,18] extends the
violated. Since such a problem could easily arise during sys- traditional notion of a test(ing) pattern to patterns intended
tem evolution, it is important to ensure that our PTCTs check for use in validating design pattern implementations. The
that constraints on the auxiliary concepts are satisfied. At the concept is similar to our use of PTCTs in that each test
same time, the fact that these constraints are typically uni- pattern specifies a particular scenario of application objects
versally quantified over the states of various roles makes this that interact in ways intended to check pattern requirements.
a challenge. This is one of the questions we intend to address However, the scenarios are not based on precise pattern spec-
in future work. ifications. Equally important, McGregor does not consider
test suite specialization, nor automated generation. Still, the
similarities are important.
5 Related work Finally, it may be useful to mention the SABER system
described by Reimer et al. [22]. The system is designed to
The PTCT testing approach builds upon our prior work in detect defects in large Java applications using static analy-
pattern formalization [12,26,31]. The key conceptual ele- sis; SABER operates on systems designed using particular
ments of this work were summarized in Section 2. Several frameworks. Correct use of these frameworks requires that
other groups have also considered improving the precision of certain methods be invoked in certain orders, that others not
pattern descriptions. Some have described techniques based be invoked at certain points, etc. SABER attempts to iden-
on diagrammatic notations that extend standard UML(-like) tify violations of such requirements based on call sequence
syntax [7,21,32]. Closer to our specification approach is that rules specified using an XML dialect. Given the importance
of Eden et al. [9,10]; the authors describe an approach to cap- of call sequence requirements in pattern-based systems,
turing the structural properties of patterns using a logic nota- elements of SABER may be useful in detecting pattern
tion. Patterns are expressed as logic formulae that specify violations statically, prior to pattern testing. We intend to
participating classes, methods, inheritance hierarchies, and explore this possibility as part of future work.
the structural relations among them. Mikkonen [19] describes
a behavioral specification approach based on DisCo [14], a
UNITY-like [5] action system notation. Data tuples represent 6 Conclusion
objects, and guarded actions model their interactions. Helm
et al. [13] describe a contract formalism that bears similarity We began with the observation that design patterns play
to ours. In particular, the formalism has constructs analogous a central role in software practice, influencing the design
to our role contracts, auxiliary concepts, and a limited form of of most major software systems and class libraries. Conse-
trace conditions. The formalism additionally provides some quently, techniques for ensuring the correctness of pattern
support for contract specialization and system-level reason- implementations are likely to have a profound impact on the
ing. However, despite the effort invested in documenting pat- reliability of real-world systems. To this end, we focused
terns precisely, there appears to be relatively little prior work on an approach to testing pattern implementations based
in testing the correctness of systems constructed according on precise pattern specifications. Whereas our prior work
to particular pattern descriptions, either formal or informal. provides the specification foundation, the work reported
By contrast, this has been the focus of our work. here provides the foundation for specification-based testing
Some readers may take note of the fact that the phrase of pattern implementations.
“test(ing) patterns” appears throughout the literature. In developing the testing approach, we observed that pat-
Indeed, there is at least one workshop series devoted to testing tern implementations follow a similar structure. This is not
patterns [28–30], a corresponding online repository [16], and surprising. After all, for a designer to claim that a particu-
widely referenced books that detail the subject [3,18]. So how lar group of classes have been designed according to a given
123
84 N. Soundarajan et al.
pattern, she must have satisfied certain requirements— during testing, use PCT to generate appropriate test cases.
namely, those common to all applications of the pattern in Hence, PCT and TDD are fully compatible, but orthogonal
question. It then follows that the test cases used to vali- testing principles.
date the pattern’s implementation share a common structure
across systems designed using the pattern. The central moti-
vation of our testing approach is that this common structure,
References
applicable to all systems designed using the pattern, should
be reusable. In defining the test cases for a particular system, 1. Baudry B, Le Sunyé Y, Jézéquel J (2001) Towards a ‘safe’ use of
testers should only be required to invest the incremental effort design patterns to improve OO software testability. In: The 12th
necessary to specialize the generalized structure as appropri- international symposium on software reliability engineering, IEEE
Computer Society, Washington, DC, pp 324–329
ate to the system under test. Moreover, the ability to define
2. Beck K, Gamma E (1998) Test infected: programmers love writing
reusable test case structures enables the software engineer- tests. Java Rep 3(7): 37–50
ing community to encode test case families that are likely to 3. Binder R (1999) Testing object-oriented systems. Addison-
reveal the most common pattern implementation errors. Wesley, Menlo Park
4. Buschmann F, Meunier R, Rohnert H, Sommerlad P, Stal M
We described a testing approach that satisfies these goals,
(1996) Pattern-oriented software architecture: a system of patterns.
and the design of a software tool used to assist in test case gen- Wiley, New York
eration. In our approach, pattern test case templates (PTCTs) 5. Chandy K, Misra J (1988) Parallel program design. Addison-
are used to define generalized test case structures reusable Wesley, Menlo Park
6. Dasiewicz P (2005) Design patterns and object-oriented software
across applications of particular patterns. Each template is
testing. In: The 2005 Canadian conference on electrical and com-
expressed using a Java-like syntax amenable to practitioner puter engineering, IEEE Canada, Dundas
adoption; the code is written in terms of the role types and role 7. Dong J (2002) UML extenstions for design pattern compositions.
methods specified by the corresponding pattern specification. In: Mingins C (ed) Proceedings of TOOLS, in special issue of
journal of object technology, vol 1, issue 3, pp 149–161
To test the behavior of a system implemented using a partic-
8. Dong J, Alencar P, Cowan D (2001) A behavioral analysis
ular pattern, the corresponding PTCTs must be instantiated approach to pattern-based composition. In: Proceedings of the 7th
to generate executable test cases. The instantiation process international conference on object-oriented information systems,
is guided by a specification of the mappings between pat- Springer, pp 540–549
9. Eden A (2001) Formal specification of object-oriented design. In:
tern roles and system classes, as well as rules that govern
Proceedings of the international conference on multidisciplinary
system-specific specializations. JDUnit assists in the instan- design in engineering
tiation process by guiding developers in selecting the appro- 10. Eden A (2002) LePUS: a visual formalism for object-oriented
priate PTCTs and pattern specifications, and in introducing architectures. In: Proceedings of the 6th world conference on inte-
grated design and process technology, IEEE Computer Society,
application-specific objects, method calls, and arguments.
pp 149–159
The output of the tool is a set of JUnit test cases used to 11. Gamma E, Helm R, Johnson R, Vlissides J (1995) Design patterns:
validate the correctness of the relevant patterns as applied in elements of Reusable OO Software. Addison-Wesley, Menlo Park
the system under test9 . 12. Hallstrom J, Soundarajan N, Tyler B (2006) Amplifying the ben-
efits of design patterns. In: Aagedal J, Baresi L (eds) Proceedings
We conclude with a short comment on the relationship
of the 9th international conference on fundamental approaches to
between our approach to pattern-centric testing (PCT), and software engineering (FASE), Springer, pp 214–229
test-driven-development (TDD) [2]. In TDD, test cases that 13. Helm R, Holland I, Gangopadhyay D (1990) Contracts: specifying
capture the expected behavior of a component are written behavioral compositions in object-oriented systems. In: OOPSLA-
ECOOP, pp 169–180
before the component is implemented. Hence, TDD dictates
14. Järvinen H, Kurki-Suonio R (1991) Disco specification language:
when test cases must be designed. On the other hand, PCT is marriage of actions and objects. In: Proceedings of the 11th inter-
concerned with what must be tested. One could, as dictated by national conference on distributed computing systems, IEEE Com-
TDD, develop our test cases before a system is implemented. puter Society, Los Alamitos, pp 142–151
15. Jones C (1990) Systematic software development using VDM.
(Of course, relevant portions of the design must be complete
Prentice-Hall, Englewood Cliffs, New York
since otherwise we would not know which PTCTs to instan- 16. Marick B (2007 (date of last access)) Test patterns repository/
tiate.) Alternatively, following a more conventional process, software testing patterns. http://www.testing.com/test-patterns/
we may design and implement the system first, and then, patterns/
17. McGregor J (1999) Testpatterns: please stand by. J Object-oriented
Program 12:14–19
9 A key guideline for using the JUnit framework is that the tests should 18. McGregor J, Sykes D (2001) A practical guide to testing object-
be designed to test behavior rather than individual methods [20]. This oriented software. Addison-Wesley, Menlo Park
also applies to our approach, except that the behaviors in question are 19. Mikkonen T (1998) Formalizing design patterns. In: Proceedings
those corresponding to the use of a particular pattern. Hence, the PTCTs of 20th ICSE, IEEE Computer Society Press, pp 115–124
typically involve multiple roles. Consequently, the instantiated test cases 20. Rainsberger J (2005) JUnit recipes. Manning
involve multiple system classes, by contrast to more traditional unit 21. Reenskaug T (1996) Working with objects. Prentice-Hall, Engle-
tests. wood Cliffs
123
Patterns: from system design to software testing 85
22. Reimer D, Schonberg E, Srinivas K, Srinivasan H, Alpern B, 27. Soundarajan N, Hallstrom J (2006) Pattern-based system evolu-
Johnson R, Kershenbaum A, Koved L (2004) “saber”: smart analy- tion: a case-study. In: Zhang K, Spanoudakis G, Visaggio G (eds)
sis based error reduction. In: Proceedings of “ISSTA ’04”, ACM Proceedings of 18th international conference on software engineer-
Press, pp 243–251 ing and knowledge engineering (SEKE 2006), Knowledge Systems
23. Riehle D (1997) Composite design patterns. In: Proceedings of Institute, pp 321–326
OOPSLA, ACM, pp 218–228 28. Testing (2001) Patterns of software testing 1
24. Schmidt D, Stal M, Rohnert H, Buschmann F (1996) Pattern- 29. Testing (2001) Patterns of software testing 2
oriented software architecture: patterns for concurrent and net- 30. Testing (2001) Patterns of software testing 3
worked objects. Wiley, New York 31. Tyler B, Hallstrom J, Soundarajan N (2006) A comparative study of
25. Shalloway A, Trott J (2002) Design patterns explained. Addison- monitoring tools for pattern-centric behavior. In: Hinchey M (ed)
Wesley, Menlo Park Procedings of 30th IEEE/NASA sofware engineering workshop
26. Soundarajan N, Hallstrom J (2004) Responsibilities and rewards: (SEW-30), IEEE-Computer Society
specifying design patterns. In: Finkelstein A, Estublier J, 32. Vlissides J (1998) Notation, notation, notation. C++ Report
Rosenblum D (eds) Proceedings of 26th international conference
on software engineering (ICSE), IEEE Computer Society, pp 666–
675
123