|
From: Vincent M. <vm...@us...> - 2001-08-21 11:11:45
|
Update of /cvsroot/mockobjects/mockobjects-java/doc/xdocs
In directory usw-pr-cvs1:/tmp/cvs-serv11809/xdocs
Modified Files:
endotesting.xml
Log Message:
original endo testing paper (PDF) available as a link in endotesting.xml
Index: endotesting.xml
===================================================================
RCS file: /cvsroot/mockobjects/mockobjects-java/doc/xdocs/endotesting.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- endotesting.xml 2001/08/05 20:13:19 1.1
+++ endotesting.xml 2001/08/21 11:11:43 1.2
@@ -17,10 +17,11 @@
<s1 title="Endo-Testing: Unit Testing with Mock Objects">
<note>
- This paper was presented at the conference, "eXtreme Programming and
+ This paper was presented at the conference, "eXtreme Programming and
Flexible Processes in Software Engineering - XP2000". <br/>
(c) 2000 Tim Mackinnon, Steve Freeman, Philip Craig. To be published in
- <em>XP eXamined</em> by Addison-Wesley.
+ <em>XP eXamined</em> by Addison-Wesley. The original paper is
+ available <link href="misc/mockobjects.pdf">here</link> (PDF format).
</note>
<p>
@@ -124,7 +125,7 @@
validate the inputs they have received from our unit test. In the
following example, <code>JUnitCreatorModel</code> is an object that
generates test classes in the VisualAge workspace, and
- <code>myMockPackage</code> and <code>myMockWorkspace</code> are Mock
+ <code>myMockPackage</code> and <code>myMockWorkspace</code> are Mock
Object implementations of interfaces provided with VisualAge:
</p>
@@ -134,7 +135,7 @@
new MockType(EXISTING_CLASS_NAME));
myMockWorkspace.addPackage(mockPackage);
- JUnitCreatorModel creatorModel =
+ JUnitCreatorModel creatorModel =
new JunitCreatorModel(myMockWorkspace, PACKAGE_NAME);
try {
@@ -148,21 +149,21 @@
]]></source>
<p>
- There are two important points to note here. First, this test
- does not test VisualAge, it only tests one piece of code that we have
- written or, with test-driven programming, are about to write. The
- full behaviour is exercised during functional testing. Second, we
- are not trying to rewrite VisualAge, only to reproduce those
- responses that we need for a particular test. Most of the methods of
- a mock implementation do nothing or just store values in local
- collections. For example, the implementation of the class
+ There are two important points to note here. First, this test
+ does not test VisualAge, it only tests one piece of code that we have
+ written or, with test-driven programming, are about to write. The
+ full behaviour is exercised during functional testing. Second, we
+ are not trying to rewrite VisualAge, only to reproduce those
+ responses that we need for a particular test. Most of the methods of
+ a mock implementation do nothing or just store values in local
+ collections. For example, the implementation of the class
<code>MockPackage</code> might include:
</p>
<source><![CDATA[
public class MockPackage implements Package {
private Vector myContainedTypes = new Vector();
- ...
+ ...
public void addContainedType(Type type) {
myContainedTypes.add(type);
}
@@ -216,7 +217,7 @@
</p>
</s2>
-
+
<s2 title="Why use Mock Objects ?">
<s3 title="Localising Unit Tests">
@@ -236,7 +237,7 @@
</p>
<p>
- For example, we might have a method on a class
+ For example, we might have a method on a class
<code>Employee</code> that updates names and details atomically :
</p>
@@ -280,8 +281,8 @@
]]></source>
<p>
- This technique is very easy to implement in modern development
- environments, especially given industry standard interfaces such
+ This technique is very easy to implement in modern development
+ environments, especially given industry standard interfaces such
as JDBC.
</p>
@@ -294,8 +295,8 @@
single piece of functionality. A unit test that depends on complex
system state can be difficult to set up, especially as the rest of
the system develops. Mock Objects avoid such problems by
- providing a lightweight emulation of the required system state.
- Furthermore, the setup of complex state is localised to one
+ providing a lightweight emulation of the required system state.
+ Furthermore, the setup of complex state is localised to one
Mock Object instead of scattered throughout many unit tests.
</p>
@@ -303,9 +304,9 @@
One of the authors of this chapter worked on a project tool that
released code from VisualAge to another source control system. As
the tool grew, it became increasingly hard to unit test because
- the cost of resetting the environment rose dramatically. The
+ the cost of resetting the environment rose dramatically. The
project tool was later refactored to use mock implementations of
- both VisualAge and the source control system. The result was
+ both VisualAge and the source control system. The result was
both easier to test and better structured.
</p>
@@ -315,10 +316,10 @@
<p>
Some unit tests need to test conditions that are very difficult to
- reproduce. For example, to test server failures we can write a
- Mock Object that implements the local proxy for the server. Each
- unit test can then configure the proxy to fail with an expected
- problem and the developers can write client code to make the test
+ reproduce. For example, to test server failures we can write a
+ Mock Object that implements the local proxy for the server. Each
+ unit test can then configure the proxy to fail with an expected
+ problem and the developers can write client code to make the test
pass. An example of this is
</p>
@@ -341,17 +342,17 @@
<p>
With this approach, the mock server runs locally and fails in a
controlled manner. The test has no dependencies on components
- outside the development system and is insulated from other
- possible real world failures. This style of test is repeated
- for other types of failure, and the entire test suite documents
+ outside the development system and is insulated from other
+ possible real world failures. This style of test is repeated
+ for other types of failure, and the entire test suite documents
the possible server failures that our client code can handle.
</p>
<p>
In the case of an expensive widget, we define similar unit
tests. We can configure the mock widget with the desired state and
- check that it has been used correctly. For example, a unit test
- that checks that the widget is polled exactly once when a
+ check that it has been used correctly. For example, a unit test
+ that checks that the widget is polled exactly once when a
registration key is sent would be
</p>
@@ -383,24 +384,24 @@
<p>
Domain objects often fail some time after an error occurs, which
- is one reason that debugging can be so difficult. With tests that
- query the state of a domain object, all the assertions are made
- together after the domain code has executed. This makes it
- difficult to isolate the exact point at which a failure occurred.
- One of the authors of this chapter experienced such problems
- during the development of a financial pricing library. The unit
- tests compared sets of results after each calculation had
- finished. Each failure required considerable tracing to isolate
- its cause, and it was difficult to test for intermediate values
+ is one reason that debugging can be so difficult. With tests that
+ query the state of a domain object, all the assertions are made
+ together after the domain code has executed. This makes it
+ difficult to isolate the exact point at which a failure occurred.
+ One of the authors of this chapter experienced such problems
+ during the development of a financial pricing library. The unit
+ tests compared sets of results after each calculation had
+ finished. Each failure required considerable tracing to isolate
+ its cause, and it was difficult to test for intermediate values
without breaking encapsulation.
</p>
<p>
On the other hand, a mock implementation can test assertions each
time it interacts with domain code, and so is more likely to fail
- at the right time and generate a useful message. This makes it
- easy to trace the specific cause of the failure, especially as
- the failure message can also describe the difference between the
+ at the right time and generate a useful message. This makes it
+ easy to trace the specific cause of the failure, especially as
+ the failure message can also describe the difference between the
expected and actual values.
</p>
@@ -431,13 +432,13 @@
<p>
Without Mock Objects, each unit test tends to have its own set of
assertions about the domain code. These may be refactored into
- shared methods within a unit test, but the developer has to
- remember to apply them to new tests. Such assertions are built
- into Mock Objects and so are applied by default whenever the
- object is used. As the suite of unit tests grows, a Mock Object
- will be used throughout the system and its assertions applied to
- new code. Similarly, as the developers discover new assertions
- that need to be made, these can be added once in a Mock Object
+ shared methods within a unit test, but the developer has to
+ remember to apply them to new tests. Such assertions are built
+ into Mock Objects and so are applied by default whenever the
+ object is used. As the suite of unit tests grows, a Mock Object
+ will be used throughout the system and its assertions applied to
+ new code. Similarly, as the developers discover new assertions
+ that need to be made, these can be added once in a Mock Object
where they will automatically apply to all existing tests.
</p>
@@ -446,14 +447,14 @@
assertions in their Mock Objects have failed unexpectedly. Usually
this is a timely warning about a constraint that the programmers
have forgotten, but sometimes this is because the failing
- constraints are not always relevant. These cases suggest
- candidates for refactoring of either the domain code or Mock
- Objects, and help to push the developers toward a better
+ constraints are not always relevant. These cases suggest
+ candidates for refactoring of either the domain code or Mock
+ Objects, and help to push the developers toward a better
understanding of the system.
</p>
</s4>
-
+
</s3>
<s3 title="Effects on Coding Style">
@@ -559,9 +560,9 @@
</p>
<p>
- Instead, we can write a handler object to reify this
- dialogue between a writer and a <code>Person</code>.
- <code>Person</code> would then have a method to pass its internal
+ Instead, we can write a handler object to reify this
+ dialogue between a writer and a <code>Person</code>.
+ <code>Person</code> would then have a method to pass its internal
contents to a handler :
</p>
@@ -581,13 +582,13 @@
</p>
<source><![CDATA[
- void testPersonHandling() {
+ void testPersonHandling() {
myMockHandler.setExpectedName(NAME);
myMockHandler.setExpectedAge(AGE);
myMockHandler.setExpectedTelephone(TELEPHONE);
-
+
myPerson.handleDetails(myMockHandler);
-
+
myMockHandler.verify();
}
]]></source>
@@ -602,13 +603,13 @@
void testPersonPrintHandler() {
myMockPrintWriter.setExpectedOutputPattern(
".*" + NAME + ".*" + AGE + ".*" + TELEPHONE + ".*");
-
+
myPrintHandler.name(NAME);
myPrintHandler.age(AGE);
myPrintHandler.telephone(TELEPHONE);
-
+
myPrintHandler.writeTo(myMockPrintWriter);
-
+
myMockPrintWriter.verify();
}
]]></source>
@@ -678,7 +679,7 @@
]]></source>
<p>
- would then return to the <code>Person</code> class and adjust any
+ would then return to the <code>Person</code> class and adjust any
method signatures to use the new interface :
</p>
@@ -690,7 +691,7 @@
<p>
This approach ensures that the interface will be the minimum that
- the domain code needs, following the Extreme Programming principle
+ the domain code needs, following the Extreme Programming principle
of not adding features beyond our current understanding.
</p>
@@ -804,7 +805,7 @@
<source><![CDATA[
public class ExpectationList implements Verifiable {
- public ExpectationList(String failureMessage);
+ public ExpectationList(String failureMessage);
public void addExpected(Object expectedItem);
public void addActual(Object actualItem);
public void verify() throws AssertionFailedException;
@@ -846,36 +847,36 @@
<s2 title="References">
- <p>
- [Beck2000] K. Beck. <em>Extreme Programming.</em>Addison-Wesley,
+ <p>
+ [Beck2000] K. Beck. <em>Extreme Programming.</em>Addison-Wesley,
2000.<br/>
[Binder2000] R. V. Binder. <em>Testing Object-Oriented Systems :
Models, Patterns, and Tools</em>. Addison-Wesley, 2000.<br/>
- [C2] Various Authors. <em>SingletonsAreEvil.</em> On-line at
+ [C2] Various Authors. <em>SingletonsAreEvil.</em> On-line at
<link href="http://c2.com/cgi/wiki?SingletonsAreEvil">
http://c2.com/cgi/wiki?SingletonsAreEvil</link><br/>
- [Gamma+1995] R. Gamma, R. Helm, R. Johnson, J. Vlissides.
- <em>Design Patterns: Elements of Reusable Object-Oriented
+ [Gamma+1995] R. Gamma, R. Helm, R. Johnson, J. Vlissides.
+ <em>Design Patterns: Elements of Reusable Object-Oriented
Software</em>. Addison-Wesley, 1995.<br/>
- [Lieberherr+1989] K. J. Lieberherr, I. M. Holland. "Assuring
- Good Style for Object-Oriented Programs." <em>IEEE Software</em>
+ [Lieberherr+1989] K. J. Lieberherr, I. M. Holland. "Assuring
+ Good Style for Object-Oriented Programs." <em>IEEE Software</em>
Volume 6, Number 5, pp. 38-49, September 1989.<br/>
- [Mackinnon2000] T. Mackinnon. <em>JunitCreator</em>. On-line at
+ [Mackinnon2000] T. Mackinnon. <em>JunitCreator</em>. On-line at
<link href="http://www.xpdeveloper.com/cgi-bin/wiki.cgi?JunitCreator">
http://www.xpdeveloper.com/cgi-bin/wiki.cgi?JunitCreator</link>.<br/>
- [Stroustrup1994] B. Stroustrup. <em>The Design and Evolution of
+ [Stroustrup1994] B. Stroustrup. <em>The Design and Evolution of
C++</em>. Addison-Wesley, 1994.<br/>
</p>
-
+
</s2>
<s2 title="Acknowledgments">
-
+
<p>
- We would like to thank the reviewers and the following colleagues
- for their contributions to this chapter: Tom Ayerst, Oliver Bye,
- Richard Karcich, Matthew Cooke, Sven Howarth, Tung Mac, Peter Marks,
- Ivan Moore, John Nolan, Keith Ray, Paul Simmons, and J. D.
+ We would like to thank the reviewers and the following colleagues
+ for their contributions to this chapter: Tom Ayerst, Oliver Bye,
+ Richard Karcich, Matthew Cooke, Sven Howarth, Tung Mac, Peter Marks,
+ Ivan Moore, John Nolan, Keith Ray, Paul Simmons, and J. D.
Weatherspoon.
</p>
|