Академический Документы
Профессиональный Документы
Культура Документы
.
*
^
WUi4jn-\\c-li'y
Q.
$&
;.'
, |
!: ,
~* !:|
Kent Beck
Addison-Wesley
An imprint of Addison Wesley Longman, Inc.
Reading, Masachusetts Harlow, England Menlo Park, California
Berkley, California Don Mills, Ontario Sydney
Bonn Amsterdam Tokyo Mexico City
'*,
? ,-* -
18
-^
*;<\
hi
*"?
< Stn
r l
^*
-
--
2003
:
.
.
.
.
.
.
.
32.973.2-018
681.3.06
42
.
: .
. .: , 2003. 224 : .
ISBN 5-8046-0051-6
, , ,
.
? , ,
. TDD (Test-Driven-Development , ). ?
. TDD ,
.
, TDD.
TDD,
, TDD. ,
.
ISBN 5-8046-0051-6
ISBN 0-321-14653-0 (.)
, 196105, -, . , . 67.
05784 07.09.01.
005-93, 2; 95 3005 .
14.08.03. 70x100/16. . . . 18,06. 3000. 297
,
198005, -, , 29
.10
.11
15
16
17
I.
21
1.
22
2.
29
3.
32
4.
36
5.
39
6. ,
.42
7.
47
8.
49
9.
53
10. times()
58
11. . .
63
12. , -
66
13.
71
14.
76
15.
81
16. , -!
85
17.
?
89
89
90
JUnit
91
92
92
93
.
95
I I . xUnit
97
18. xUnit
98
19. ( setup)
104
20. ( tearDown)
108
21.
112
22.
115
23.
118
24. xUnit
123
I I I .
125
25. ,
126
126
(Isolated Test)
(Test List)
(Test First)
assert (Assert First) .
(Test Data)
(Evident Data)
128
129
131
132
134
135
26.
One Step Test ( )
Starter Test ( )
Explanation Test ( )
Learning Test ( )
Another Test ( )
Regression Test ( )
Break ()
Do over ( )
Cheap Desk, Nice Chair ( , )
136
136
137
139
139
140
141
141
143
144
27.
(Child Test)
Mock Object ( )
Self Shunt ()
Log String (-)
Crush Test Dummy ( )
145
145
146
147
149
149
Broken Test ( ) . . .
Clean Check-in ( )
7
151
151
28.
Fake It ()
Triangulate ()
Obvious Implementation ( )
One to Many ( )
153
153
155
156
157
29. xUnit
Assertion
Fixture ()
External Fixture ( )
Test Method ( )
Exception Test ( )
All Tests ( )
159
159
161
163
164
166
166
30.
Command ()
Value Object (-)
Null Object (-)
Template Method ( )
Pluggable Object ( )
Pluggable Selector ( )
Factory Method ( )
Imposter ()
Composite ()
,
Collecting Parameter ( )
Singleton ()
168
170
170
172
173
175
176
178
179
180
182
183
31.
Reconcile Differences ( )
Isolate Change ( )
Migrate Data ( )
Extract Method ( )
Inline Method ( )
Extract Interface ( ) . . .
Move Method ( )
Method Object ( )
Add Parameter ( )
Method Parameter to Constructor Parameter (
)
32. TDD
?
?
?
. 184
184
185
186
188
189
190
191
192
193
193
195
195
196
196
TDD ?
?
?
TDD?
TDD
?
?
TDD
?
TDD?
TDD ?
TDD ?
TDD ?
?
TDD
?
TDD
197
198
200
201
201
202
203
204
205
205
206
208
208
210
211
I.
213
214
215
I I .
217
220
, (clean code that works), ,
, (Ron Jeffries),
Test-Driven Development (TDD). ,
, , , .
. ,
,
.
, .
, ,
, .
.
,
.
.
, ?
, ,
. ,
, .
, Test Driven Development (TDD).
:
, ;
.
, ?
:
,
, , ;
,
, - ;
;
, ,
.
11
TDD
.
1. , , ,
.
2. ,
.
, .
3. .
TDD.
, , ,
,
, , ,
. , , ,
, :
,
(Quality Assurance, QA)
() ;
,
,
;
,
,
;
, ,
,
.
, , ?
,
? ,
?
.
TDD .
.
, , ,
, . : !,
: !
,
:
12
,'
;
;
;
.
, . ,
,
,
;
,
;
, ,
,
;
( .)
.
, ,
. , ,
. ,
, .
, ,
, . ,
.
TDD . ,
, , .
, , .
, , . .
, ,
.
Extreme Programming Explained
(Extreme Programming) TDD (Test-Driven
Development). TDD .
: , ,
. TDD . TDD
,
,
. ,
, ,
"? TDD? , TDD.
,
.
13
, TDD, ,
. (test infected)
(Erich Gamma) ,
. TDD, ,
, , ,
. ,
, TDD,
, TDD ,
.
, , ( ,
) . , TDD
. ,
, ,
.
, ,
, .
, :
;
;
,
.
.
I. . ,
TDD.
(Ward Cunningham) ,
TDD. :
,
. ,
, ,
.
II. xUnit. ,
Reflection API .
.
xUnit,
.
,
.
III. .
, ,
, xUnit.
,
, .
14
,
. , ,
,
,
. ,
, ,
,
. ,
, , ,
, .
. ,
,
. ,
(
). ,
. , ,
, . ,
,
, ,
, ,
.
. TDD .
,
.
,
. , ,
: (Steve Freeman), (Frank
Westphall), (Ron Jeffries), (Dirk Koning),
(Edward Heiatt), (Tammo Freese), (Jim Newkirk), (Johannes Link), (Manfred Lange),
(Steve Hayes), (Alan Francis), (Jona
than Rasmusson), (Shane Clauson), (Simon Crase),
(Kay Pantecost), (Murrey Bishop),
(Ryan King), (Bill Wake), (Edmund Schweppe),
(Kevin Lawrence), (John Carter), (Phlip),
(Peter Hansen), (Ben Schroeder), (Alex Chaf
fee), (Peter van Rooijen), (Rick Kawala),
(Mark van Hamersveld), (Doug Swartz),
(Laurent Bossavit), (Ilia Preuz), (Daniel Le Berre),
(Frank Carver), (Mike Clark),
(Christian Pekeler), (Karl Scotland), (Carl Manaster), . . (J. . Rainsberger), (Peter Lindberg), (Darach Ennis), (Kyle Cordes), (Justin
Sampson), (Patrik Logan), (Darren Hobbs),
(Aaron Sansone), (Syver Enstad), (Shinobu Kawai), (Erik Meade), (Patrik Logan), (Dan Rawsthorne), (Bill Rutiser), (Eric Her
man), (Paul Chisholm), (Asim Jalis),
(Ivan Moor), (Levi Purvis), (Rick Mugridge),
(Antony Adachi), (Nigel Thome), (John Bley),
(Kari Hoijarvi), (Manuel Amago), Kaopy (Kaouru Hosokawa), (Pat Eyler), (Ross Shaw),
(Sam Gentle), Qean Rajotte), (Phillipe Antras) (Jaime Nino).
. ,
.
, ,
TDD. ,
. ,
16
, ,
comp@piter.com ( , ).
!
web- http://www.piter.com
.
(Ward Cunningham)
, WyCash.
,
.
, . :
. , ,
. ,
. :
?
, . ,
, . ,
,
, , .
WyCash
.
, . ,
,
(Guaranteed Investment Contracts),
.
WyCash - ,
.
Dollar, .
.
Dollar. ,
Smalltalk ,
.
, , ,
,
, .
, Dollar.
, 1,
\
1
c2.com/doc/oopsla91.html.
18
. ,
, Dollar ...
,
, .
, . ,
, , ,
, AveragedColumn.
.
, , , .
.
, .
,
.
,
: , ? ,
, .
Dollar
.
, . 2
43 - 15 USD 200 CHF1.
,
Dollar (), Currency (). ,
,
PolyCurrency ().
, ,
, . , ?
Currency ( ) ;
. .
, .
.
WyCash ,
. , -
.
:
WyCash
, ,
.
USD , CHF . . .
19
WyCash,
( , , ).
,
; ,
.
, ; ,
-
. , ,
. ,
. ,
(
, , ),
?
, . ,
,
, . Test-Driven Development (
), TDD ,
, ,
, . , .
. ,
,
:
,
, ;
.
,
, . ,
, (multi-currency
money).
,
( ,
).
(Test-Driven
Development, TDD). , TDD
:
1. .
2. , .
3. .
4. ,
.
5. (refactoring)
.
, :
,
?
, ,
?
?
?
, WyCash,
(. ). , .
IBM
GE
1000
400
25
100
25 000
40 000
. 65 000
, .
IBM
Novartis
1000
400
150 CHF
25 000 USD
60 000 CHF
65 000 USD
USD
, CHF
USD
1,5
23
, ,
, .
, . ,
, DOT . ,
.
, . ,
? .
, . ( ,
, , .)
. , ?
, .
, ?
.
, ,
. , .
, ,
(API)
, ,
.
1:
public void testMultiplicationO {
Dollar five new Dollar(5);
five.times(2);
assertEqualsdO. five.amount);
}
(, : , ,
. ? , -
2, . , ,
3.)
$5 + 10 CHF = $10, 2:1
5 * 2 = $10
amount
Dollar?
?
, , ,
. ( , ,
1
2
times() * . . .
(code that smells) , (
). . .
JUnit, .
, . ,
. . .
24
, JUnit.)
( )?
:
Dollar;
;
times(int);
() amount
, . (
.) , Dollar
Dollar
class Dollar
, .
, , , -
.
Dollar
Dollar(int amount) {
}
. times().
, :
Dollar
void timesdnt multiplier) {
}
. ,
() amount.
Dollar
int amount:
! , :
. 1.1.
. (JUnit
) , ,
, 10 0.
...
! .
. , , - .
, .
. .
, ,
, .
.
25
Runs:
1/1
errors: Failures:
0
1
testMultipllcation(MoneY.MoneyTe80:expect*d:<10 butwas:0>
1
jFinished: 0.11 seconds
. 1.1. !
, ,
:
Dollar
i n t amount= 10:
JUnK
Test class name:
. - ' - II - 1
HMoneyMoneyTest
E Retoad classes everyrun
J
Rims:
Errors: Futures:
1 / 1 0
0
f
Run
_
<i
.-.:.: :,
"..-:...?
II
i
^ k i l e h i * 0.11 seconds
1.2.
1.2 .
, .
26
, ! , .
, ,
.
, .
, TDD :
1. .
2. , , - .
3. .
4. , .
5. .
(Steve Freeman) ,
( , , ).
,
. ,
, .
.
SQL, ,
, ,
.
.
, .
. ,
.
,
, - ,
.
TDD. , ,
, .
,
. ?
,
. ? , :
Dollar
i n t amount= 5 * 2 ;
, 10. ,
, , . 5 2
, .
10. 5 2 ,
,
. .
, 5 2 ,
. () amount
timesQ?
27
Dollar
int amount:
void timesdnt multiplier) {
amount= 5 * 2 :
}
, .
.
? , TDD
,
.
? . ,
.
. ,
, , .
,
, .
. ? ,
. 5?
,
amount:
Dollar
Dollardnt amount) {
this.amount= amount:
}
amount,
timesQ:
Dollar
void times(int multiplier) {
amount= amount * 2;
}
multiplier 2,
:
Dollar
void times(int multiplier) {
amount= amount * multiplier;
}
, Java,
*= (, , ):
Dollar
void times(int multiplier) {
amount *= multiplier:
}
28
I
$5 + 10 CHF = $10, 2:1
$ 5 * 2 = $10
amount
Dollar?
?
.
; .
:
, ;
,
;
J Unit;
, ;
, ;
, ;
,
.
:
1. . ,
. , ,
, , .
2. .
. , .
, .
, ,
.
( ),
.
, , .
3. . , ,
.
, , ,
.
, ( (Ron Jeffries) ).
,
( ). , , !
, , .
,
, ,
, .
$5 + 10 CHF = $10, 2:1
$5 * 2 - $10
amount
Dollar?
?
30
, :
Dollar . :
public void testMultiplicationO {
Dollar five= new Dollar(5):
five.times(2);
assertEqualsdO, five.amount):
five.timesO):
assertEquals(15. five.amount);
}
,
. times()
. times() ,
,
. , Dollar,
. , ,
,
.
public void testMultiplicationO {
Dollar five= new Dollar(5):
Dollar product= five.times(2);
assertEquals(10. product.amount):
product five.timesO):
assertEquals(15. product.amount):
}
,
Dollar.times():
Dollar
Dollar timesdnt multiplier) {
amount *= multiplier:
return null:
}
, . !
, Dollar
:
Dollar
Dollar times(int multiplier) {
return new DollarCamount * multiplier):
}
'
$5 + 10 CHF = $10, 2:1
$5*2 = $10
amount
Dollar?
?
31
1, ,
, .
, (
, ).
, , .
.
:
, , (Fake It)
,
;
(Obvious Implementation)
.
TDD
. , ,
( ,
, , , ).
,
, . ,
.
, , (Triangulation),
3. . :
( ) ,
(- );
, ;
, .
(, ,
) (,
Dollar) TDD. ,
.
. ,
-.
.
, ,
.
1, ,
, .
. ,
1 , ,
(, ,
, ).
,
Dollar. Value Object (-
). ,
.
Value Object
, (aliasing). ,
$5, $5
.
,
.
(aliasing).
Value Objects,
(aliasing). ($5),
($5). -
$7, .
$5 + 10 CHF = $10, 2:1
$5*2 = $10
amount
Dollar?
?
equals()
Value Objects ,
, -
33
, , true "5==5", ,
, "amount==5", "amount==dollar.amount".
,
(Triangulation).
,
, ( ),
,
( , ).
.
, ,
, .
().
,
.
, . ,
$5 I- $6?
public void testEqualityO {
assertTrue(new Dollar(5).equals(new Dollar(5)));
2 * 297
34
$5 * 2 - $10
amount
Dollor?
?
equalsO
hashCodeQ
times(). $5*2 = $10 $5 * 3 - $15,
.
, . ,
, . ,
,
. ,
?
,
.
( ,
)? , , ,
.
$5 + 10 CHF = $10, 2:1
$5 * 2 - $10
amount
Dollar?
?
hashCode()
null
, (equality) .
null ?
, ,
.
, ,
Dollar. amount ,
35
.
, :
, Value Object
;
;
;
( , );
, , .
$5*2 = $10
amount
D Dollar?
?
equolsQ
hashCodeO
null
, (equality),
. , Dollar.times()
Dollar,
( ), .
:
public void testMultiplicationO {
Dollar five= new Dollar(5);
Dollar product= five.times(2);
assertEquals(10. product.amount);
product^ five.timesO):
. assertEquals(15, product.amount);
}
(assert-) ,
Dollar:
public void testMultiplicationO {
Dollar five= new Dollar(5);
Dollar product=five.times(2):
assertEquals(new Dollar(lO), product);
product= five.timesO):
assertEquals(15. product.amount);
}
'
37
, :
public void testMultiplicationO {
Dollar five new Dollar(5):
Dollar product=five.times(2);
assertEquals(new Dollar(lO). product):
product five.timesO):
assertEqualsCnew Dollar(15). product):
}
product,
:
public void testMultiplicationO {
Dollar five new Dollar(5):
assertEqua1s(new Dollar(lO), five.times(2)):
assertEquals(new 0(15), five.times(3)):
}
, .
. Dollar amount, :
Dollar
private i n t amount;
$5 + 10 CHF = $10, 2:1
$5 * 2 - $10
amount
D Dollar?
?
cqualsO
hashCodeO
null
. ,
:
, ,
. TDD .
. ,
, .
, .
, , .
(-
, ).
, :
;
38
, ,
;
, ;
.
$5 * 2 - $10
amount (private)
Dollar?
?
equalsO
hashCode()
null
5 CHF * 2 = 10 CHF
,
? , .
,
. , Dollar,
, .
Franc. Franc
, Dollar, ,
,
.
Franc , Dollar, ,
Dollar:
public void testFrancMultiplicationO {
Franc five= new Franc(5):
assertquals(new Franc(lO). five.times(2));
assertEquals(new Franc(15). five.timesO)):
}
(, 4
Dollar.
. , ,
, .)
40
.
? Dollar Dollar Franc.
. -. ,
.
(copy-and-paste)?
?
?
, ,
. ? ,
.
,
:
1. .
2. , .
3. , .
4. , .
5. .
, . ,
,
. TTD ,
. ,
.
TTD
. .
, .
, .
. ,
, : ,
! .
.
. .
! , ,
, (make it run, make it right).
. , ,
,
. ? , .
(
).
Franc
class Franc {
private int amount:
Francdnt amount) {
41
this.amount amount;
}
Franc timesdnt multiplier) {
return new Franc(anraunt * multiplier);
}
public boolean equals(Object object) {
Franc franc= (Franc) object;
return amount franc.amount;
}
}
$5 + 10 CHF = $10, 2:1
$5 * 2 - $10
amount (privotc)
Dollar?
?
equalsQ
hashCode()
null
5 CHF * 2 - 10 CHF
Dollar/Franc
equals()
times()
, - ,
, (Make it compile).
.
, . ,
equals(). .
,
.
:
, ;
;
,
;
,
.
$5 * 2 - $10
omount (private)
Dollar?
?
hashCode()
null
5 1 1 * 2 - 10
Dollar/Franc
equals()
times()
,
Dollar
Franc
43
Money
Dollar
Franc
. 6.1.
Money
equals(). :
Money
class Money
, - . ,
, ,
.
Dollar Money:
Dollar
class Dollar extends Money {
private i n t amount:
}
? . .
amount Money:
Money
class Money {
protected i n t amount:
}
Dollar
amount :
private protected.
. (
, Money,
Dollar,
.)
equals() ,
Money.
:
Dollar
public boolean equals(Object object) {
Money dollar= (Dollar) object:
return amount == dollar.amount:
}
- .
.
44
Dollar
public boolean equals(0bject object) {
Money dollar (Money) object:
return amount == dollar.amount:
}
,
:
Dollar
public boolean equalsCObject object) {
Money money= (Money) object:
return amount money.amount:
}
Dollar Money:
Money
public boolean equalsCObject object) {
Money money (Money) object:
return amount money.amount;
}
Franc.equals().
, ,
Franc, , , Dollar,
, . ,
, .
, , TDD
, .
,
. ,
, ,
. ,
. ?
- , ,
. , ,
, - . ,
.
. ,
. . .
. .
. ,
.
, .
Dollar:
public void testEqualityO {
assertTrue(new Dollar(5).equals(new Dollar(5)));
45
}
. !
. .
, , Franc
Money:
Franc
class Franc extends Money {
private i n t amount;
}
amount Franc,
Money:
Franc
class Franc extends Money {
}
Franc.equalsO , Money.equals().
,
Franc.
. :
Franc
public boolean equals(Object object) {
Money franc= (Franc) object:
return amount == franc.amount:
}
:
Franc
public boolean equals(Object object) {
Money franc= (Money) object;
return amount == franc.amount;
}
, , ,
, Money.
-
:
Franc
46
I
$5 + 10 CHF = $10, 2:1
$5 * 2 - $10
amount (private)
Dollar?
?
hashCodeO
null
5 CHF * 2 - 10
Dollar/Franc
equolsf)
times()
(Franc) (Dollar)
Franc.equals() Money.equals(),
Franc.
. .
?
7.
:
(Dollar)
(Money);
(Franc) (Money);
equals()
Franc.
-> j M
amount (privote)
Dollar?
?
cquols()
hashCode()
null
5 * 2 - 10 CHF
Dollar/Franc
cquals()
times()
(Franc) (Dollar)
6 : ,
?
. .
, ?
public void testEqualityO {
assertTrue(new Dollar(5).equals(new Dollar(5))):
assertFa1se(new Dollar(5).equals(new Dollar(6))):
assertTrue(new Franc(5).equa1s(new Franc(5)));
assertFa1se(new Franc(5).equa1s(new Franc(6))):
assertFa1se(new Franc(5).equals(new Dollar(5))):
}
.
. ,
.
, . ,
,
Money ,
amount .
48
Money
public boolean equals(Object object) {
Money money= (Money) object;
return amount =*= money.amount
&& getClassO.equals(money.getClassO):
}
,
, . ,
, ,
Java.
, ,
,
. , , .
$5 + 10 CHF = $10, 2:1
$5*2 = $10
amount (private)
D Dollar?
?
equals()
hashCode()
null
5 CHF * 2 = 10 CHF
Dollar/Franc
equals()
times()
! 1 (Franc) (Dollar)
?
times(),
.
, :
;
, ,
getClass();
-
, .
50
Dollar
Money times(int multiplier) {
return new Dollar(amount * multiplier)
}
. ,
Money, .
.
, TDD.
? ,
, .
Money (Factory Method),
Dollar.
:
public void testMultiplicationO {
Dollar five= Money.dollar(5);
assertEquals(new Dollar(lO). five.times(2)):
assertEquals(new Dollar(15), five.times(3)):
}
Dollar :
Money
static Dollar dollar(int amount) {
return new Oollar(amount):
}
Dollar,
:
public void testMultiplication() {
Money five= Money.dollar(5):
assertEquals(new Dollar(lO). five.times(2));
assertEquals(new Dollar(15). flve.timesO)):
}
, times() Money
. ,
Money ( ?)
Money.times():
Money
abstract class Money
abstract Money times(int multiplier);
:
Money
static Money dollarCint amount) {
return new Dollar(amount):
}
51
, , , .
:
public void testMultiplicationO {
Money five= Money.do!lar(5);
' assertEquals(Money.do11ar(10), five.times(2)):
assertEquals(Money.dollar(15), five.timesO)):
}
public void testEqualityO {
assertTrueCMoney.dol1ar(5).equals(Money.dol1ar(5))):
assertFalseCMoney.dollar(5).equals(Money.dollar(6))):
assertTrue(new Franc(5).equals(new Franc(5)));
assertFalse(new Franc(5).equals(new Franc(6)));
assertFalse(new Franc(5).equals(Money.dollar(5))):
}
, .
Dollar.
,
, - .
testFrancMultiplication(),
, -
, testMultiplication().
: testFrancMultiplication()?
, ? ,
, .
public void testEqualityO {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.dollar(6))):
assertTrue(Money.franc(5).equals(Money.franc(5)));
assertFalse(Money.franc(5).equals(Money.franc(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5))):
}
public void testFrancMultiplicationO {
Money five= Money.franc(5):
assertEquals(Money.francdO). five.t1mes(2)):
assertEquals(Money.franc( 15), five.timesO)):
}
Money.franc() ,
Money.dollar():
Money
static Money francdnt amount) {
return new Franc(amount):
}
52
I
$5 + 10 CHF = $10, 2:1
$5 * 2 - $10
amount (private)
Dollar?
?
equals()
hashCodeO
null
5 * 2 - 10
Dollar/Franc
equalsQ
times()
(Franc) (Dollar)
?
testFrancMultiplicationQ?^
times().
, :
, times();
;
,
;
, ,
, .
$5 * 2 -" $10
amount (private)
Dollar?
?
cquals()
hashCode()
null
5 * 2 10
Dollar/Franc
equals()
times()
(Franc) (Dollar)
?
testFrancMultiplication()?
- ,
? ,
?
?
! !
, :
? , .
, ,
Flyweight Factory () ,
.
:
public void testCurrencyO {
assertEquals("USD". Money.do!lar(l).currencyO):
assertEquals("CHF". Money.franc(1).currency());
}
54
currency () Money:
Money
abstract String currencyO:
:
Franc
String currencyO {
return "CHF":
}
Dollar
String currencyO {
return "USD";
}
,
currencyO- (
, .
, ,
. -, , ,
.)
Franc
private String currency:
FrancCint amount) {
this.amount = amount;
currency "CHF";
}
String currencyO {
return currency:
}
To Dollar:
Dollar
private String currency;
Do11ar(int amount) {
this.amount = amount:
currency = "USD";
}
String currencyO {
return currency:
}
currencyO Money, :
Money
protected String currency:
String currencyO {
55
return currency:
}
"USD" "CHF"
, ,
.
:
Franc
Franc(int amount. String currency) {
this.amount = amount:
this.currency = "CHF":
}
:
Money
static Money franc(int amount) {
return new Franc(amount, null);
}
Franc
Money times(int multiplier) {
return new Franc(amount * multiplier, null):
}
-! Franc.timesO
, ?
? ,
, .
, ,
( Jim
Coplien). , times()
:
Franc
Money timesdnt multiplier) {
return Money.franc(amount * multiplier):
}
"CHF":
Money
, :
Franc
56
I
this.currency - currency:
}
,
. ? .
,
,
.
. ,
, ,
. ,
Dollar :
Money
static Money dol1ar(int amount) {
return new Dollar(amount,"USD");
}
Dollar
Dollar(int amount, String currency) {
this.amount = amount;
this.currency = currency:
}
Money t1mes(int multiplier) {
return Money.dollar(amount * multiplier):
}
. !
TDD. ,
? .
? . TDD
, , .
- , ,
.
,
:
Money
57
$ * 2 - $10
omount (private)
Dollar?
?
equols()
hashCode()
null
5*2- 10
Dollar/Franc
equols()
times()
(Franc) (Dollar)
?
testFrancMultiplication()?
times() .
, :
,
, ,
;
,
( );
,
times() ;
Dollar
;
.
timesQ
$5 + 10 CHF = $10, 2:1
$ 5 * 2 $10
amount (private)
Dollar?
?
cquals()
hashCode()
null
5 CHF * 2 - 10 CI1
Dollar/Franc
equals()
times()
(Fronc) (Dollar)
?
testFrancMultiplication()?
Money,
. times() ,
:
Franc
Money timesdnt multiplier) {
return Money.franc(amount * multiplier):
}
Dollar
Money times(int multiplier) {
return Money.dollar(amount * multiplier):
}
, ,
, ,
, . , -
10 times()
59
new? ( ,
, new
. ,
. , ,
.)
Franc
Money timesCint multiplier) {
return new Franc(amount * multiplier. "CHF");
}
Dollar
Money times(int multiplier) {
return new Oollar(amount * multiplier. "USD");
}
, Franc currency
"CHF\ :
Franc
Money times(int multiplier) {
}
. ,
Franc Money? ,
,
, , ,
. ,
.
. TDD,
, 5 10
, 15
. , .
, , ,
. , ,
.
, ,
Franc.timesO Money:
Franc
Money timesCint multiplier) {
return new Money (amount * multiplier, currency):
}
60
, Money (
) :
Money
class Money
Money times(int amount) {
return null:
}
.
: expected:<Money.Franc@31aebf> but was:<Money.Money@478a43>. He -
. , .
, toString():
Money
public String toStringO {
return amount + " " + currency:
, ! ?! ? ,
toStringO, , :
;
toStringO , ,
, ;
,
, .
.
: expected :< 10
CHF> but was: < 10 CHF>. , .
,
. equals():
Money
public boolean equals(Object object) {
Money money = (Money) object;
return amount == money.amount
&& getClassO.equals(money.getClassO);
}
,
.
, .
,
, .
, ,
. .
equalsQ,
.
10 times()
61
. (
, ,
, .)
Franc
. ,
Franc(10,"CHF") Money(10,"CHF"), ,
. :
public void testOifferentClassEqualityO {
assertTrue(new MoneydO, "CHF").equals(new FrancdO. "CHF"))):
}
, . equal()
, :
Money
public boolean equals(Object object) {
Money money - (Money) object:
return amount == money.amount
&& currencyO.equals(money.currencyO);
}
Franc.times() Money,
- :
Franc
Money times(int multiplier) {
return new Money(amount * multiplier, currency);
}
DoHar.times()?
Dollar
Money timesdnt multiplier) {
return new Money (amount * multiplier, currency):
}
! ,
.
Money
62
I
$5 + CHF = $10, 2:1/
$5 * 2 - $10
amount (private)
Dollar?
?
equals()
hashCode()
null
5 CHF * 2 - 10 CHF
Dollar/Franc
equalsQ
times()
() (Dollar)
?
testFrancMultiplicationO?
, ,
.
:
times(),
, (Inline Method),
;
toString() ;
(
Money Franc) , ,
;
,
.
$5 * 2 - $10
amount (private)
Dollar?
?
equalsO
hashCode()
null
5 * 2 - 10
Dollar/Franc
equals()
timcs()
(Franc) (Dollar)
?
testFrancMultiplication()?
, Dollar Franc, ,
,
. .
,
. Franc:
Franc
static Money francdnt amount) {
return new Money (amount. "CHF"):
}
Dollar:
Dollar
64
Dollar , .
Franc:
public void testDlfferentClassEquality() {
assertTrue(new MoneydO, "CHF").equals(new FrancdO. "CHF")));
}
,
, .
:
public void testEqualityO {
assertTrue(Money.dollar(5).equals(Money.dollar(5))):
assertFalse(Money.dollar(5).equals(Money.doll ar(6))),
assertTrue(Money.franc(5).equals(Money.franc(5)));
assertFalse(Money.franc(5).equals(Money.franc(6)));
assertFalse(Money.franc(5).equals(Money.dollar(5))):
}
,
. , .
assert,
:
public void testEqualityO {
assertTrue(Money.dollar(5).equals(Money.dollar(5)));
assertFalse(Money.dollar(5).equals(Money.doll a r ( 6 ) ) ) :
assertFalse(Money.franc(5).equals(Money.dollar(5))):
}
$5 + 10 CHF = $10, 2:1
$ 5 * 2 = $10
amount (private) 1
Dollar?
?
eqaalsO
hashCode()
null
..5 * 2-1 10
Dollar/Franc
equals()
times()
() (Dollar)
?
testFrancMultiplication()?
testDifferentClassEqualityO , ,
, , .
,
. Dollar -
11
65
Franc. ,
: Money. ,
testDifferentClassEqualityO . ,
Franc.
,
.
, , ,
, ( ,
). ,
testFrancMultiplication(), , -
.
,
.
. :
;
,
,
.
3 .297
,
-
, ,
.
. (
. , ,
,
. - ,
, . .)
$5 + 10 CHF = $10, 2:1
$5 + $5 = $10
,
,
: $5 + $5 = $10.
public void testSimpleAddition<) {
Money sum Money.dollar(5).plus(Money.donar(5)):
assertEquals(Money.dollar(10). sum);
}
, Money.dollar( 10),
. :
Money
Money pi us(Money addend) {
return new Money(amount + addend.amount, currency):
}
( ,
. , ,
. , ,
TDD .)
12 , -
67
, ,
. ,
.
.
.
? ,
.
,
, , ,
- . ,
, .
,
( ,
).
(
) .
,
,
.
. ,
, ,
, .
Imposter ().
, .
Imposter ()?
,
.
. ,
. , TDD
. , TDD
, ,
,
.
, ?
, Money,
Money. ,
. ,
.
.
: (expression).
, : (2 + 3) * 5.
, : ($2 + 3 CHF) * 5.
Money .
Expression.
68
Sum1. (,
) ,
Expression .
.
? , ,
:
public void testSimpleAdditionO {
assertEquals(Money.dollardO). reduced):
}
reduced Expression,
Expression, -
.
? . , ,
:
public void testSimpleAdditionO {
Money reduced= bank, reduce (sum. "USD"):
assertEquals(Money.dollar(10), reduced):
}
(, :
.
. , , ,
- .)
: reduce()
bank. :
...reduced= sum.reduceC'USD", bank).
reduce()
bank? : ,
, .
reduce()
Bank, Expression?
:
Expression ,
. , ,
.
(
,
).
sum . . .
12 , -
69
, Expression
. ,
, . Expression
.
, ,
- ,
, . ,
, Bank,
reduce() Expression.
bank, , :
public void testSimpleAddition() {
Bank bank= new BankO;
Money reduced bank.reduce(sum. "USD");
assertEquals(Money.dollar(10). reduced);
}
Money Expression:
public void testSi mpl eAddi t i o n O {
Expression sum= f i v e . p l u s ( f i v e ) :
Bank bank= new BankO;
Money reduced= bank.reduceCsum, "USD"):
assertEquals(Money.dollar(10). reduced);
}
, , ,
:
public void testSi mpleAddi t i on() {
Money five= Money.dollar(5):
Expression sum= f i v e . p l u s ( f i v e ) :
Bank bank= new BankO:
Money reduced= bank.reduce(sum. "USD");
assertEquals(Money.dollar(10). reduced);
}
, ?
Expression ( ,
):
Expression
interface Expression
70
, Money Expression (
, ):
Money
class Money implements Expression
, Bank:
Bank
class Bank
reduceQ:
Bank
. !
! :
Bank
! .
. :
,
( $5 + 10 CHF
$5 + $5);
;
;
;
, ;
, ,
, .
$5 + $5 ,
. .
, $10
:
Bank
Money reduceCExpression source. String to) {
return Money.dollar(10);
*
}
$5 + $5 :
public void testSimpleAdditionO {
Money five= Money.do11ar(5):
Expression sum= five.pi us(five);
Bank bank= new BankO:
Money reduced= bank.reduce(sum, "USD");
assertEquals(Money.dollar(10). reduced);
}
, , ,
.
.
, . ,
, .
$5 + 10 CHF = $10, 2:1
$5 + $5 = $10
$5 + $5 Money
72
( - ,
augend, addend}
, .)
.
,
.
, ,
1. , Sum
: augend addend:
Sum
class Sum {
Money augend;'
Money addend:
}
Sum :
Sum
Sum(Money augend, Money addend) {
, Sum Expression:
Sum
class Sum implements Expression
, - ,
Sum ( -
13
73
, ,
):
Sum
Bank.reduce() Sum.
, , Money,
.
public void testReduceSumO {
Expression sum= new Sum(Money.do11ar(3). Money.dollar(4));
Bank. bank= new BankO:
Money result= bank.reduce(sum, "USD"):
assertEquals(Money.dollar(7). result);
}
,
. ( reduce())
Sum , (
) Money, (amount)
Money, Sum,
(currency) :
Bank
Money reduce(Expression source. String to) {
Sum sum= (Sum) source:
i n t amount= sum.augend.amount + sum.addend.amount:
return new Money(amount, t o ) ;
}
:
( Sum),
Expression;
.
. Sum
.
Bank
74
I
return new Money(amount, t o ) :
}
. (reduce)
, Sum .
Bank, , ,
Sum.reduceQ Bank.
.
, . ( ,
, - ,
, , .)
, * Bank.reduce()
Money?
, ,
- :
public void testReduceMoney() {
Bank bank= new BankO;
Money resu1t= bank. reduce(Money.dol l a r d ) . "USD");
assertEquals(Money.dol1ar(l), result):
}
Bank
Money reduce(Expression source. String to) {
i f (source instanceof Money) return (Money) source:
Sum sum= (Sum) source;
return sum.reduce(to);
}
! !
. ,
, . Sum
reduce(String), Money
, reduce(String) Expression.
Bank
Money reduce(Expression source. String to) {
i f (source instanceof Money)
return (Money) source.reduce(to):
Sum sum= (Sum) source;
return sum.reduce(to):
}
Money
public Money reduce(String to) {
return t h i s ;
}
13
75
reduce(String) Expression:
Expression
Money reduce(String t o ) ;
:
Bank
Money reduce(Expression source. String to) {
return source.reduce(to):
}
$5 + $5 = $10
$5 + $5 Money
Bank.reduce(Money)
Money
Reduce(Bank,String)
.
:
,
;
, ,
;
, , ,
, ( Sum);
( Sum);
,
, , ;
, . ().
, , (
(embrace
change))1. ,
. :
public void testReduceMoneyDifferentCurrencyO {
Bank bank= new BankO;
bank.addRateC"CHF", "USD". 2);
Money result= bank.reduce(Money.franc(2). "USD");
assertEquals(Money.dollard), result);
}
, (
- ,
). ,
:
Money
14
77
, Money . .
, ,
, Bank. Bank
Expression.reduce(). ( ? , .
.) :
Bank
Money reduce(Expression source. String to) {
return source.reduce(this. to):
}
:
Expression
Money reduceCBank bank. String t o ) ;
Sum
(public),
( , , ).
Bank:
Bank
i n t rateCString from. String to) {
return (from.equalsCCHF") && to.equalst"USD"))
? 2
: 1:
}
bank :
Money
public Money reduceCBank bank. String to) {
i n t rate = bank.rate(currency. t o ) ;
return new Money(amount / rate, t o ) ;
} .
2 ,
. ,
Bank -
78
.
-,
.
, ? Array.equals()
?
public void testArrayEqualsO {
assertEquals(new Object[] {"abc"}. new Object[] {"abc"}):
}
. . ,
-:
Pair
private class Pair {
private String from:
private String to;
Pair(String from, String to) {
this.from- from:
this.to- to:
}
}
Pair ,
equals() hashCode().
, . ,
. , .
, -,
, ,
,
.
Pair
public boolean equals(0bject object) {
Pair pair= (Pair) object:
return from.equals(pair.from) && to.equals(pair.to);
}
public int hashCodeO {
return 0;
0 -,
, .
. ,
, ,
.
,
:
14
79
Bank
private Hashtable rates- new HashtableO;
:
Bank
void addRate(String from. String to. int rate) {
rates.put(new Pair(from. to), new Integer(rate)):
}
:
Bank
int rate(String from. String to) {
Integer rate= (Integer) rates.get(new Pair(from, to));
return rate.intValueO:
}
- ! . ?
, ,
. , USD USD
1, , .
, :
public void testldentityRateO {
assertEqualsd. new BankO.rateCUSD". "USD")):
}
,
:
Bank
int rate(String from. String to) {
i f (from.equals(to)) return 1;
Integer rate= (Integer) rates.get(new Pair(from, to));
return rate.intValueO:
}
!
$5 + 10 CHF = $10, 2:1
$5 I 5 - $10
$5 + $5 Money
Bank.rcduco(Money)
Money
Reduce(Bank,String)
, , $5 + 10
CHF. :
, , , ;
;
80
(testArrayEquals),
Java;
(private) ,
;
, ,
.
, , $5 + 10 CHF:
public void testMixedAdditionO {
Expression fiveBucks= Money.dollar(5):
Expression tenFrancs= Money.franc(lO);
Bank bank= new BankO:
bank.addRate("CHF". "USD". 2):
Money result= bank.reduce(fiveBucks.plus(tenFrancs). "USD"):
assertEquals(Money.dollar(10). result):
}
. ,
. ,
Money Expression , ,
, , .
.
. ,
.
. ,
. :
, .
(
).
public void testMixedAdditionO {
Money fiveBucks= Money.dollar(5);
82
I
Money tenFrancs= Money.franc(10);
Bank bank= new BankO:
bank.addRateC'CHF", "USD". 2):
Money result= bank.reduce(fiveBucks.plus(tenFrancs). "USD"):
assertEquals(Money.dollar(10), r e s u l t ) :
}
. 15 USD 10 USD. ,
Sum.reduce() :
Sum
public Money reduce(Bank bank. String to) {
i n t amount= augend.amount + addend.amount;
return new Money(amount, t o ) :
}
, :
Sum
public Money reduceCBank bank, String to) {
i n t amount= augend.reduce(bank, to).amount
+ addend.reduce(bank, to).amount:
return new Money(amount, t o ) :
}
, . Money
Expression. ,
. , augend addend
Expression:
Sum
Expression augend:
Expression addend:
Expression:
Sum
Sum(Expression augend. Expression addend) {
this.augend= augend:
this.addend= addend:
}
( Sum Composite, ,
.) Sum, , ,
Money?
plus() Expression:
Money
15
83
times() Expression:
Money
, Expression
plus() times(). Money .
plusQ :
public void testMixedAdditionO {
Money fiveBucks= Money.dollar(5);
Expression tenFrancs= Money.franc(10);
Bank bank= new BankO;
bank.addRateC'CHF". "USD". 2);
Money result= bank.reduce{fiveBucks.pl us(tenFrancs). "USD");
assertEquals(Money.dollardO), r e s u l t ) ;
}
tenFrancs Expression, ,
. ,
, . :
public void testMixedAdditionO {
Expression fiveBucks= Money.dollar(5):
Expression tenFrancs= Money.franc(10):
Bank bank= new BankO;
bank.addRateC'CHF". "USD". 2);
Money result= bank.reduce(fiveBucks.plus(tenFrancs). "USD");
assertEquals(Money.dollardO), r e s u l t ) ;
}
, plus()
Expression. :
Expression
Expression pi us(Expression addend);
Sum,
:
Sum
84
I
$5 t 10 IF - $10, 2:1
$5 I $5 - 10
$5 + $5 Money
Dank.rcduce(Moncy)
Reduce(Bank,String)
Sum.plus
Expression.times
.
Money Expression.
, . :
, ,
;
( );
,
(Expression fiveBucks),
( plus()
Expression . .).
,
-!
Expression.plus,
Sum.plus(). Expression.times()
. Sum.plus():
public void testSumPlusMoneyO (
Expression fiveBucks= Money.dollar(5):
Expression tenFrancs= Money.franc(lO):
Bank bank= new BankO;
bank.addRate("CHF". "USD". 2);
Expression sum= new SurrKfiveBucks. tenFrancs).plus(fiveBucks);
Money result= bank.reduce(sum. "USD"):
assertEquals(Money.dollar(15). result):
}
86
Sum
public Expression pi us(Expression addend) {
return new SunKthis. addend):
}
$5 i 10 = $10, 2:1
$5 i $5 - $10
$5 + $5 Money
Bank.rcducc(Moncy)
Money
Reducc(Bank,String)
Sum.plus
Expression.times
TDD ,
,
. TDD ,
, ,
, , .
. , ,
, ,
.
$5 i 10 CHF - $10, 2:1
$5 I $5 - $10
$5 + $5 Money
Bank.reducc(Money)
Money |
Rcducc(Sank,String)
Sum.plus
Expression.times
Sum.times(), ,
Expression.times() . :
public void testSumTimesO {
Expression fiveBucks= Money.dollar(5);
Expression tenFrancs= Money.franc(10);
Bank bank= new BankO;
bank.addRate("CHF". "USD", 2);
Expression sum= new $um(fiveBucks,tenFrancs).times(2):
Money result= bank.reduce(sum. "USD");
assertEquals(Money.dollar(20), result):
}
, , (,
J Unit, , .
Fixture () ,
xUn.it.)
16 , -!
87
Sum
Expression times(int multiplier) {
return new Sum(augend.times(multiplier).addend.times(multiplier))
}
augend addend
Expression, , ,
Expression times():
Expression
Expression times(int multiplier);
Money.times()
Sum.times() ( ):
Sum
public'Expression timesdnt multiplier) {
return new Sum(augend.times(multiplier),addend.times(multiplier));
}
Money
public Expression times(int multiplier) {
return new Money(amount * multiplier, currency):
}
$5 i 10 - $10, 2:1
5 I $5 - $10
$5 + $5 Money
Bonk.reduce(Moncy)
Money
Rcducc(Bank,String)
Sum.plus
Expression.times
.
,
$5 + $5 Money. :
public void testPlusSameCurrencyReturnsMoneyO {
Expression sum= Money.dollard).plus(Money.dollar(D);
assertTrue(sum instanceof Money):
}
,
, .
, , , ,
. , ,
:
Money
public Expression plus(Expression addend) {
return new Sum(this, addend);
}
88
I
$5 i 10 CHF - $10, 2;1
$5 I $5 = $
$5 i $5 Money
Bank.rcduce(Moncy)
Reducc(Bonk,String)
Sum.plus
Exprcssion.timcs
He ,
Money ( ,
, ).
, ( ).
. :
,
, ;
, TDD
,
;
, ;
, ,
, .
.
. ,
:
? ?
. ,
.
JUnit.
JUnit?
. .
. : .
?
. TDD
?
?
? .
Sum.plus() Money.plus().
Expression ( ,
),
.
,
. TDD ,
.
, , ,
. ,
, .
,
90
. ,
, ,
, .
,
(, SmallLint for Smalltalk).
.
.
, , .
:
? ,
, , , , .
, . ,
, ,
,
, .
, , .
?
, ?
( .)
,
,
,
.
,
( ). ,
.
( , ,
). ,
,
(
). ,
,
(expressions).
, .
, .
, . ?
, .
,
,
. , ,
.
17
91
(MoneySum),
(MoneyBag) , ,
(Wallet). ,
. ,
( Money) . , 2 USD +
+ 5 CHF + 3 USD 5 USD + 5 CHF.
.
, .
, - . ,
, , ,
,
.
,
20- ? ?
, ,
, ?
?
JUnit
JUnit
. ,
Enter 125 .
, ,
. ,
.
. 17.1 .
, , ,
.
50
45
40
35
>. 30
25
20
s. 15
10
5
0
1
<5
< 10
>= 10
. 1 7 . 1 .
92
. 17.1 .
17.1.
W
(2)
5
22
91
1,04
4,1 W
1
15
89
1
5,9
:
1. (API) ,
.
.
,
.
2. ,
(fixtures).
.
3. (cyclomatic complexity) ,
.
1,
, .
,
.
4.
.
5.
,
. 29,
xUnit.
TDD :
;
, ;
17
93
;
, ;
, .
, ,
, ,
? (
.) . 17.2
,
.
10
><
6
05
I 2
, , ,.,, ,, ,
I I I I I I I I I''
10 12 14 16 18 20 22 24 26 28
. 17.2. ,
,
, , ,
, ( ,
, , , ,
).
, ,
( )
, ,
.
,
1.
TDD. TDD
, , -
Mandelbrot, Benoit, ed. 1997. Fractals and Scaling in Finance. New York: Springer-Verlag.
94
.
:
;
;
.
,
TDD, ,
.
, TDD
,
, , , ,
.
?
:
(statement coverage).
,
.
TDD, 100 %.
. , J Probe (www.sitaka.com/software/
jprobe) ,
Money.toString(). ,
,
.
(defect insertion).
. :
, .
, ,
Jester Oester.sourceforge.net). ,
, ,
. : Pair.hash.Code().
-
: 0. ,
( ),
, .
(Phlip), ,
.
: ,
,
, (
). .
-, . ,
, TDD,
17
95
. ( 32 ,
6 , , , 65
.)
.
.
:
( ,
),
.
, ,
TDD:
, ,
: (Fake It), (Triangualation) (Obvious Implementation);
;
:
, ;
, .
II
xUnit
, ? ,
, .
xUnit Python,
Python. He
, , Python,
.
, , -,
Python, -, ,
, , -
,
TDD !
xUnit
-,
. (
! ! ! .)
.
,
, . II
,
. , ,
.
,
. : TestCase("testMethod").run(). :
,
.
,
. , , ,
, , . ,
, - ,
, . ,
,
:
setup
tearDown
tearDown ,
, - .
- ,
,
18 xUnit
99
, . ,
, ,
, .
,
.
, . ,
. .
.
.
.
WasRun1, ,
. wasRun
( , wasRun ).
( WasRun) test.
, assert test.wasRun ( assert
Python).
Python
, .
, ,
:
t e s t - WasRunC'testMethod")
print test.wasRun
test.testMethodO
print test.wasRun
, None
1 . ( Python None
null nil 0 .)
, . ,
WasRun ( !).
WasRun
class WasRun:
pass
( pass ,
.) , WasRun
wasRun.
( ), (
init ).
wasRun None ():
WasRun
class WasRun:
was . . rupee.
100
II xLlnit
def
i n i t (self, name):
self.wasRun= None
None,
,
WasRun testMethod. ( ,
: - - , . ,
? , , IDE
.)
WasRun
def testMethod(self):
pass
: None None1.
None 1. , testMethod
wasRun :
WasRun
def testMethod(self):
self.wasRun= 1
, , ! .
--! ,
, , .
, , ,
run().
:
test= WasRun("testMethod")
print test.wasRun
test.runO
print test.wasRun
,
:
WasRun
def run(self):
self.testMethod(-)
, .
,
, , ,
. ,
. , , .
Python () def,
. , .
( ). . .
18 xUnit
101
, TestCase,
.
testMethod.
Python
(.
WasRun). , ,
, .
1.
WasRun
class WasRun:
def __init (self, name):
self.wasRun= None
self.name* name
def run(self):
method = getattr(self. self.name)
method 0
: ,
, ,
,
. ,
( ).
. TDD :
TDD ,
. ,
.
WasRun :
-, , ; -,
. (
). ,
TestCase WasRun :
TestCase
class TestCase:
pass
WasRun
class WasRun(TestCase): . . .
name :
TestCage
def __init__(self, name):
self.name= name
(Duncan Booth) , ,
Python, ,
.
102
II xUnit
WasRun
def i n i t (self, name):
self.wasRun= None
TestCase. i n i t (self, name)
, ; run() ,
, , . (
.)
TestCase
def _ i m ' t _ ( s e l f . name):
self.name= name
def run(self):
method - getattKself. self.name)
method
,
, , .
,
: None 1. ,
:
TestCaseTest
class TestCaseTest(TestCase):
def testRunning(self):
test WasRunCtestMethod")
assert(not test.wasRun)
test.runO
assert(test.wasRun)
TestCaseTest("testRunning").run()
setup
tearDown
tearDown ,
print,
assert, , ,
Extract Method ( ).
. ,
, . ,
,
(,
Python).
, ,
. , ,
, TDD.
18 xLlnit
103
,
. TDD,
,
. , TDD,
, .
setUp().
.
:
, - ;
,
;
Pluggable Selector ( )
, ;
.
( setup)
, ,
( (Bill Wake)
Arrange, Act, Assert):
Arrange;
Act;
Assert.
. setup
~v tearDown
- tearDown ,
Arrange ,
.
: 7 9. , 16;
, -2; , , ,
63. ,
: 7 9.
(
), ,
.
:
. ,
. ,
, ,
.
. ,
.
19 ( setUp)
105
- , , ,
.
: ,
, ,
. ,
:
, , ,
. , , , , ,
- , , .
, . ,
.
.
WasRun, , wasRun
. :
TestCaseTest
def testSetUp(self):
test= WasRunC'testMethod")
test.runO
assert(test.wasSetUp)
,
TestCaseTest("testSetUp").run(). ,
wasSetUp . ,
. :
WasRun
def setUp(self):
self.wasSetUp= 1
setUpQ - .
setllpO TestCase. :
TestCase
def setUp(self):
pass
def run(self):
self.setUpO
method = getattr(self, self.name)
method
,
, , .
? , . - ,
, ,
.
106
xUnit
,
. WasRun,
wasRun setUp():
WasRun
def setUp(self):
self.wasRun= None
self.wasSetUp= 1
testRunning()
,
. ?
, testSetUp().
, , :
TestCaseTest
def testRunning(self):
test WasRunC'testMethod")
test.runO
assert(test.wasRun)
.
WasRun, .
WasRun setUp(), .
TestCaseTest,
. ( ,
,
.)
TestCaseTest
def setUp(self):
s e l f . t e s t - WasRunC'testMethod")
def testRunning(self):
self.test.runO
assert(self.test.wasRun)
def testSetUp(self):
self.test.runO
assert(self.test.wasSetUp)
setup
tearDown
tearDown ,
,
tearDownQ.
19 ( setup)
107
:
, ,
;
setUp() ;
setUp() ,
- ;
setUp() , ,
( ,
).
(
tearDown)
TGCTODOrO
setup
tearDown
tearDown ,
.
,
setUp(). , ,
.
tearDown(),
.
tearDown()?
.
. ,
: setUp()
, tearDown()
. ,
. ,
.
.
, , .
setup
tearDown
tearDown ,
WasRun
20 ( tearDown)
109
WasRun
def setUp(self):
self.wasRun= None
self.wasSetUp= 1
self.log= "setUp "
testSetUpO,
:
TestCaseTest
def testSetl)p(self):
self. test. runO
assert("setUp " self.test.log)
wasSetUp.
:
WasRun
def testMethod(self):
self.wasRun= 1
s e l f . l o g - self.log + "testMethod "
testSetUpQ,
"setUp testMethod ".
:
TestCaseTest
def testSetUp(self):
self.test.run()
assertC'setUp testMethod " self.test.log)
,
testRunning testSetUp:
TestCaseTest
def setUp(self):
s e l f . t e s t = WasRun("testMethod")
def testTemplateMethod(self):
self.test.run()
assert("setUp testMethod " == test.log)
WasRun ,
, setUp():
TestCaseTest
def testTemplateMethod(self):
test= WasRun("testMethod")
test.run()
assertC'setUp testMethod " == test.log)
, ,
,
. , -
110
II xLlnit
,
, , ,
. ,
.
,
, .
.
, , ,
, , .
setup
tearDown
tearDown ,
D WasRun
tearDown(). ! !
tearDown():
TestCaseTest
def testTemplateMethod(self):
test- WasRunCtestMethod")
test.runO
assert("setup testMethod tearDown " test.log)
. ,
:
TestCase
def run (self, result):
result. testStartedO
self.setUpO
method = getattrCself. self.name)
method()
self, tea rDownO
WasRun
def setUp(self):
self.1og= "setup "
def testMethod(self):
self.log= self.log + "testMethod "
def tearDown(self):
self.log= self.log + "tearDown "
WasRun, TestCaseTest
tearDownQ TestCase:
TestCase
def tearDown(self):
pass
20 ( tearDown)
111
, .
! . ,
, , .
setup
tearDown
tearDown ,
Wasftun
.
Python
.
:
;
tearDown()
;
, , ,
.
sctUp
tcorDown
tearDown ,
WoaRun
tearDown() ,
. , ,
. ( ,
, , ).
,
,
.
TDD , ,
. , ,
, , -,
, -, , ,
. ,
,
. ,
. , ,
,
.
,
, : 5, 2: TestCaseTest.testFoo ZeroDivideException, MoneyTest.testNegation AssertionError.
,
.
.
21
113
TestCase.run() TestResult,
( ,
).
TestCaseTest
def testResult(self):
test= WasRunC'testMethod")
result= test.runO
assertC'l run. 0 failed" == result.summaryO)
:
TestResult
class TestResult:
def summary(self):
return "1 run, 0 failed"
, TestResult
TestCase.run():
TestCase
def run(self):
self.setUpO
method = getattr(self. self.name)
method
self .tea rDownO
return TestResultO
, ,
summaryO . , .
:
TestResult
def i n i t (self):
self.runCount= 1
def summary(self):
return "% run. 0 failed" % self.runCount
( % Python sprintf .)
runCount , ,
, .
0,
.
TestResult
def i n i t (self):
self.runCount= 0
def testStarted(self):
self.runCount- self.runCount + 1
def summary(self):
return "% run, 0 failed" % self.runCount
114
II xLlnit
TestCase
def run(self):
result= TestResultO
result. testStartedO
self.setUpO
method = getattr(self, self.name)
method
self .tea rDownO
return result
"",
, ,
runCount, .
:
TestCaseTest
def testFailedResult(self):
test= WasRurK "testBrokenMethod")
result= test.runO
assertCl run. 1 failed", result.summary)
:
WasRun
def testBrokenMetnod(self):
raise Exception
setup
._. tearDown .
,. - tearDown ,
WosRun
,
, ,
WasRun.testBrokenMethod(), .
,
. .
. :
;
;
,
, .
:> ' 1"
setup '
. tearDown
tearDown ,
.
D WasRun
, ,
:
TestCaseTest
def testFailedResultFormatting(self):
result= TestResultO
result.testStartedO
'result.testFailedO
assertC'l run, 1 failed" result.summaryO)
: testStartedO testFailed().
, ,
. testFailedResultFormatting() ,
,
.
, ,
testStartedO testFailed()
, .
testStartedO testFailed(),
: :
116
II xUnit
TestResult
def i n i t (self):
self.runCount= 0
self.errorCount= 0
def testFailed(self):
self.errorCount= self.errorCount + 1
(
, , , ), ,
:
TestResult
def summary(self):
return "% run, % failed" % (self.runCount. self.failureCount)
, testFailed()
, .
? ,
:
TestCase
def run(self):
result= TestResultO
result. testStartedO
self.setUpO
try:
method = getattr(self, self.name)
method0
except:
result.testFailedO
self, tea rDownO
return result
:
setUpQ, . ,
.
, . (
TDD, 12 .
, .
,
,
. , ,
, ,
, .)
(
).
22
117
setup
tearDown
tearDown ,
| D WasRun
setup
,
.
:
;
;
, ,
;
, ,
,
.
"-- -setUp
-tearDown
tearDown ,
| WosRun
setup
xUnit,.He TestSuite,
. ,
, :
pri nt
print
print
print
TestCaseTest("testTemplateMethod").run().summary()
TestCaseTest("testResult").run().summary()
TestCaseTest("testFailedResultFormatting").run().summary0
TestCaseTest("testFailedResult").run().summary()
, ,
.
. ( ,
, ,
.) ,
TestSuite, ,
Composite (), ,
, .
( TestSuite),
:
23
119
TestCaseTest
def testSuite(self):
suite= TestSuiteO
suite.add(WasRun("testMethod"))
sui te.add(WasRun("testBrokenMethod"))
resu1t= suite.run()
assert("2 run, 1 f a i l e d " = result. summaryO)
, TestSuite
add(), ,
, :
TestSuite
class TestSuite:
def i n i t (self):
self.tests [ ]
def add(self, test):
self.tests.append(test)
( Python [] .)
run() . ,
TestResult , :
TestSuite
def run(self):
result= TestResultO
for test in tests:
test.run(result)
return result
120
II xUnit
TestCaseTest
def testSuite(self):
suite= TestSuiteO
suite.add(WasRun("testMethod"))
suite.add(WasRun("testBrokenMethod"))
result= TestResultO
suite.run(result)
assert("2 run. 1 failed" = result.summaryO)
run()
:
TestSuite
def rurKself, result):
for test in tests:
test.run(result)
TestCase
def run(self, result):
result. testStartedO
self.setUpO
try:
method = getattr(self. self.name)
methodO
except:
result.testFailedO
self, tea rDownO
:
suite= TestSuiteO
sui te.add(TestCaseTest("testTemplateMethod"))
suite. addCTestCaseTestC'testResult"))
suite.add(TestCaseTest("testFailedResultFormatting"))
suite.add(TestCaseTest("testFailedResult"))
suite.add(TestCaseTest("testSuite"))
result= TestResultO
suite.run(result)
print result.summary()
BLOOD setup
tearDown
tearDown ,
WasRun
setup
TestSuite TestCase
23
121
, ,
,
TestCase.
( run()
):
TestCaseTest
def testTemplateMethod(self):
test= WasRunC'testMethod")
result TestResultO
test.run(result)
assert("setup testMethod tearDown " test.log)
def testResult(self):
test= WasRunC'testMethod")
result= TestResultO
test.run(result)
assertC'l run, 0 failed" result.summaryO)
def testFailedResult(self):
test= WasRunC'testBrokeriMethod")
result= TestResultO
test.run(result)
assertC'l run. 1 failed" == result.summaryO)
def testFailedResultFormatting(self):
result= TestResultO
result.testStartedO
result.testFailedO
assertC'l run. 1 failed" == result.summaryO)
, TestResult
set(Jp().
,
:
TestCaseTest
def setUp(self):
self.result= TestResultO
def testTemplateMethod(self):
test= WasRunC'testMethod")
test.run(self.result)
assert("setup testMethod tearDown " == test.log)
def testResult(self):
test WasRunC'testMethod")
test.run(self.result)
assertC'l run, 0 failed" self.result.summaryO)
def testFailedResult(self):
test= WasRunC'testBrokeriMethod")
test.run(self.result)
assertC'l run, 1 failed" self .result. summaryO)
def testFailedResultFormatting(self):
self, result. testStartedO
122
I I xllnit
self.result.testFai ledC)
assertC'l run. 1 failed" = self.result.summaryO)
def testSuite(self):
suite= TestSuiteO
suite.add(WasRun("testMethod"))
suite. add(WasRun("testBrokenMethod'"))
suite.run(self.result)
assert("2 run. 1 f a i l e d " self.result.summaryO)
sotUp
tcorDown
tearDown ,
! iHc i
| WasRun
-
setUp
TestSuite TestCase
self ,
Python . -
, , ,
. Python
( , ).
,
self .
.
, TDD .
, , :
TestSuite;
,
( ,
, ,
, ,
);
(),
, , ,
, ;
setUpQ.
xUnit
, , II ,
. ,
. ,
, ,
,
.
TDD.
xUnit
30 . ,
, ,
xUnit. - , , ,
xUnit
. :
. xUnit
. (Martin Fowler) :
,
.
, xUnit
.
xUnit, ,
.
.
, xUnit.
- ,
.
xUnit, ,
assert
, .
assert . - -
124
II xLlnit
xUnit assert
: GUI
.
JUnit Test,
TestCase TestSuite. ,
,
JUnit, Test
:
public interface Test {
public abstract int countTestCasesO:
public abstract void rundestResult result):
}
()
.
countTestCases()
TestResult ,
TestCases.
HI
,
.
TDD,
, , .
,
,
TDD.
,
, ,
, .
J
J
,
:
?
?
?
?
?
.
.
,
( ,
, ,
). , , ,
. , ,
.
, :
,
. :
.
:
25 ,
127
,
: .
?
. 25.1
( (Gerry Weinberg)
Quality Software Management). ,
.
,
.
-___.
25.1.
, ?
,
. ,
. , ,
. :
.
, ?
, , .
.
.
? 25.1 .
, ,
. . , . . ,
. , . ,
, .
, !
,
.
, . ,
. ,
.
,
, ? ,
. ... .
, ( -
128
III
,
). :
, ,
, (
)? ,
. ,
. . , .
.
. ,
(
).
, ,
, :
. . .
... ,
,
. , ,
.
(Isolated Test)
? .
,
. (,
, !)
.
. ,
(
, ,
,
). ,
, ,
. , ,
,
. (, !)
, , .
.
,
, .
, . -,
,
.
25 ,
129
, - . -, ,
.
, ,
,
, .
,
,
. :
: ,
.
,
.
, .
,
.
. , ,
. , ,
.
, ,
. , ,
, ,
.
,
.
,
. , ,
. ,
,
.
, , ,
, ,
.
, .
(Test List)
? ,
, .
, :
, ,
. , ,
.
5
297
130
III
. ,
. ,
, .
, ,
. , ,
. ,
, .
.
, .
,
.
. ,
,
. , ,
. ,
, ( )
.
, ,
, .
, . ,
, , -
. , ,
, .
,
? ,
. -,
, .
, . , , , ,
, .
, ,
(,
, , ,
.) ,
,
.
,
. -, ,
. ,
.
, .
,
.
" ^^^^
25 ,
131
, ,
, , .
.
, ,
.
. ,
,
. TDD
:
.
,
.
. .
.
<> . ,
.
,
.
,
.
,
, .
,
. , ,
, , .
(Test First)
?
.
. ,
.
, .
( - ):
; ( )
; , ,
.
. ,
. , ,
. .
, ?
?
: -
132
III
,
, , ,
.
, , ,
. ,
, ,
, - -
.
. , ,
.
25 ,
133
?
, ?
, ,
, .
:
?
?
. ,
. . ,
abc.
testCompleteTransactionO {
assertTrue(reader.isClosedO);
assertEqualsC'abc", reply.contentsO);
}
reply? , :
testCompleteTransactionO {
Buffer reply= reader.contentsO:
assertTrue(reader.isClosed());
assertEqualsC'abc", reply.contentsO);
}
? , :
testCompleteTransactionO {
Socket reader= Socket ("local host", defaultPortO):
Buffer reply= reader.contentsO:
assertTrue(reader.i sClosed()):
assertEqualsC'abc". reply.contentsO):
}
:
testCompleteTransactionO {
Server writer= Server(defaultPort(). "abc"):
Socket reader= SocketC'localhost". defaultPortO);
Buffer reply= reader.contentsO;
assertTrue( reader. i sCl osedO):
assertEqualsC'abc". reply.contentsO);
}
,
, .
assert.
134
III
(Test Data)
?
, . ,
.
,
. ,
.
1 2, 1.
,
, , .
,
.
. ,
pJus(),
2 + 2 . ,
: 1 + 1
. ,
, .
2 + 2 , ,
. , ,
plus()
( ,
, ,
plus() , ,
). ,
2 3
( 3 + 4
Smalltalk).
Test Data ( ) Realistic
Data ( ),
.
:
,
,
;
( );
,
, ,
, ,
.
25 ,
135
(Evident Data)
?
.
, . , -
: ,
?
, ,
.
. ,
1,5 . ,
(USD) (GBP).
2:1. $100,
50 GBP - 1,5 % =* 49,25 GBP. :
Bank bank= new Bank().
bank.addRate("USD". "GBP", STANDARD_RATE);
bank.commission(STANDARD_COMMISSION);
Money result= bank.convert(new NotedOO, "USD"), "GBP");
assertEquals(new Note(49.25. "GBP"), r e s u l t ) :
:
Bank bank= new BankO:
bank.addRate("USD". "GBP". 2):
bank.commission(0.015);
Money result= bank.convert(new NotedOO, "USD"). "GBP");
assertEquals(new NotedOO / 2 * (1 - 0.015), "GBP"), result);
,
, .
Evident Data ( ) :
.
assert, ,
. ,
.
Fake It ( ) ,
, .
Evident Data ( ) ,
, . ,
.
,
.
, ,
, .
26
137
, , ? ! ! ,
. . ,
, , ,
.
, ,
( ), ,
. , ,
( ),
.
,
. -,
.
, ,
(Growth) : ,
. -, ,
, .
, ,
.
,
.
Starter Test ( )
?
, -
, .
,
: ? ,
, ,
. ,
. , ,
.
,
:
?
?
?
,
. ,
.
.
138
III
?
. :
,
,
. 3 + 4 = 7. .
,
, ,
(),
. ,
.
, (),
.
, ,
, ?
Starter Test ( ), :
J , .
.
. ,
.
:
Reducer r= new Reducer(new PolygonO);
assertEqua1s(0. reducer.result().npoi nts);
! .
...
One Step
Test ( ): - ,
,
. ,
.
, .
- ,
, .
,
. , . :
StartServer
Socket= new Socket
Message= "hello"
Socket.write(message)
AssertEquals(message. socket.read)
: ,
..>
26
139
Explanation Test ( )
?
, - .
, TDD/
. ,
TDD,
, , ,
.
. ,
.
.
,
. TDD
, .
, ,
.
?
: -, , Foo
, , , 76?
, : .
Foo , , 76.
Foo , ,
67.
. -
,
. ,
.
Learning Test ( )1
,
?
.
, ,
Mobile Information Device Profile (MIDP)
Java. RecordStore
. ,
? .
1
140
III
. ,
.
, ,
, API , .
, :
RecordStore store;
public void setup {
store= RecordStore.openRecordStore("testing", true):
}
public void tearDownO {
RecordStore.deleteRecordStore("testi ng");
}
'
API , ,
.
,
.
,
. .
, ,
. ,
.
Another Test ( )
?
, ,
.
( ,
, , ).
,
.
, , , ,
, . ,
!
26
141
,
.
. , .
.
(, , )
.
, ,
. , ,
.
, .
Regression Test ( )
, ?
, ,
.
,
, .
, ,
,
, , .
.
, .
. ,
, ,
.
, ,
. , ,
: .
Break ()
, ?
.
, .
, , ,
, .
,
. , - ,
: -
142
I I I
! . .
.
, , , ,
.
-
? , , ?
, ?
(Dave Ungar) (Shower Metho
dology). , , . , ,
, , .
,
, . TDD
. ,
, (Obvious Implementation).
, , (Fake It).
- , (Triangulate). -
, , , , .
. 26.1 , .
. ,
, .
.
. 26.1. ,
,
.
.
,
.
.
-.
, .
( ,
.)
,
. -
26
143
.
,
. ,
,
, .
. ,
, , , ,
, .
:
, ,
. - .
, , ,
. ,
.
Do over ( )
, ? .
. . .
. . ,
, ,
, . ,
, 20 ,
.
, .
. . ,
.
, .
. 25 ,
.
(Tim
Mackinnon).
. ,
.
. ,
,
.
,
.
, ,
, , . ,
: , , - v
-?
144
III
(Child Test)
, ?
,
. . .
. ,
, .
: ,
, ,
. .
.
, , ,
, . ?
, ?
, .
,
. , , ,
.
,
, ,
. ( , .
, ! ---! ! ,
.
,
. , , .
,
.)
146
III
. .
, , , .
.
Mock Object ( )
,
? ,
.
.
, 1.
.
. ,
,
, ,
,
. ,
.
,
.
, ,
.
public void testOrdertookupO {
Database db= new MockDatabaseO;
db.expectQueryCselect orderjio from Order where custjio is 123");
db.returnResult(new String[] {"Order 2" ."Order 3"}):
}
MockDatabase ,
. , ,
(result set),
.
: .
, ,
, 14 . ,
, 14 , ,
.
,
(
Singleton ()). ,
, www.mockobjects.com.
27
147
, ,
, .
.
(Massimo Arnoldi) ,
, .
,
.
,
, ( ,
, ) Exchange (
) ,
. , .
,
.
, .
,
, ? ,
,
, ,
.
Self Shunt ()
,
?
, .
, ,
.
TestResult, ,
, , , ,
, , . ,
, .
:
ResultListenerTest
def testNotification(self):
result= TestResultO
listener= ResultListenerO
result.addListener(1istener)
WasRun("testMethod").run(result)
' assert 1 == listener.count
, :
ResultListener
class ResultListener:
148
III
def
i n i t (self):
self.count= 0
def startTest(self):
self.count= self.count + 1
-! Listener?
TestCase. TestCase
(Mock Object).
ResultListenerTest
def testNotification(self):
self.count= 0
result= TestResultO
result.addLi stener(self)
WasRunC"testMethod").run(result)
assert 1 == self.count
def startTest(self):
self.count= self.count + 1
, Self Shunt (
), , , , .
. 0, 1.
.
1? , - startTest().
startTest()?
.
count ,
count 0
1 .
, Self Shunt ()
Extract Interface ( ),
,
. , :
.
, ,
, ,
.
Self Shunt ()
, Java
.
,
. Java
, .
.
,
, ,
.
27
149
:
WasRun
def setUp(self):
self.log= "setUp "
def testMethod(self):
self.log= self.log + "testMethod "
def tearDown(self):
self.log= self.log + "tearDown "
150
III
.
? ? ,
, .
, ,
, .
? .
. Fake
It ().
File:
private class FullFile extends File {
public FullFileC'String path) {
super(path);
}
public boolean createNewFileO throws IOException {
throw new IOExceptionO;
}
}
:
public void testFileSystemErrorO {
File f= new FullFileC'foo");
try {
saveAs(f):
failO:
} catch (IOException e) {
}
}
Mock Object ( ),
.
(inner)
Java. ,
,
:
public void testFileSystemErrorO {
File f= new FileC'foo") {
public boolean createNewFileO throws IOException {
throw new IOExceptionO;
}
}:
try {
saveAs(f):
failO:
} catch (IOException e) {
.
}
}
'
27
151
Broken Test ( )
,
? .
(Richard Gabriel).
. ,
, , .
, . ,
,
,
, , ,
, ,
, .
.
, , .
, , .
, ,
. ,
.
,
. . ,
, .
,
, .
Clean Check-in ( )
( ,
? .
'
? .
(Bubba Whitman), Walt's stevedore brother
, ,
. ,
, ,
, .
, , ,
. ( ,
.
, , ,
.)
152
III
, ,
,
. ( ,
,
.) , ,
?
. ,
, ,
. ,
, ,
,
.
.
, :
. ,
:
,
. , - ,
.
, .
,
, .
,
( ).
Fake It ()
, ?
, .
,
.
xUnit. :
return "1 run, 0 failed"
:
return "%6 run. failed" % self.runCount
. :
return "%6 run. %6 failed" % (self.runCount . self failureCount)
Fake It () ,
, .
i ( ,
). ,
, (
, ,
).
Fake It () -5 . , ?
154
III
, - ,
, ,
. (Peter Hansen)
:
TDD
. ,
, ,
. , ,
.
,
? , ,
. ,
, . ,
.
Fake It ()
:
. ,
, .
, , .
.
.
.
,
.
.
, , .
Fake It () ,
, ? ,
. ,
1:
assertEquals(new MyDate("28.2.02"). new MyDate("1.3.02").yesterdayO);
MyDate
public MyDate yesterday0 {
.
:
MyDate
public MyDate yesterdayO {
(Dierk K6nig) .
28
155
- . ,
MyDate("1.3.02") this ( ). :
MyDate
public MyDate yesterday() {
return new MyOate(this.daysO-l);
}
'
,
(Triangulation) ,
. , Fake It ()
Obvious Implementation ( ).
Triangulate ()
? ,
.
. , ,
. :
public void testSumO {
assertEquals(4, plus(3. D ) :
}
private int plusO'nt augend, int addend) {
return 4;
}
,
:
public void testSumO {
assertEquals(4. plus(3. D ) :
assertEquals(7. plus(3.4)):
}
, ,
plus() :
private int pi us(int augend, int addend) {
return augend + addend;
}
,
. Fake It ()
.
, .
156
I I I
,
. assert
plus(),
assert, . ,
, pius() ,
.
assert.
, ,
.
Fake It () Obvious Implementation (
).
Obvious Implementation ( )
?
.
Fake It () Triangulate ()
. ,
. ! , . ,
Fake It () -
, plus()? , .
.
,
.
Fake It () Triangulate ()
. , ,
, . ,
, 1.
. ,
, ,
?
? ! .
: , (clean code that
works).
, .
,
.
Obvious Implementation ( )
, .
: ,
. , .
. - . -
(Laurent Bossavit) .
28
157
...
/ .
. .
, ,
.
One to Many ( )
, ?
,
.
, , ,
. :
public void testSumO {
assertEquals(5. sum(5)):
}
private int sumdnt value) {
return value;
}
( sum() TestCase,
.)
sum(new int[] {5, 7}).
sum() , :
public void testSumO {
assertEquals(5. sum(5, new i n t [ ] {5})):
}
private int sumdnt value, i n t [ ] values) {
return value;
}
Isolate
Change ( ). ,
, .
:
private int sum(int value, i n t [ ] values) {
int sum= 0:
for (int i= 0; i<values.length: i++)
sum + values[i]:
return sum:
}
:
public void testSumO {
assertEquals(5, sum(new i n t [ ] {5}));
}
158
III
Isolate Change (
). , .
, :
public void testSumO {
assertEquals(12, sum(new i n t [ ] {5. 7 } ) ) ;
xLlnit
> ,
xUnit.
Assertion
, ?
, ,
.
, ,
,
,
\ . , ' , .
, :
:
(True) , ,
, ;
- assert().
assertTrue(rectangle.area() != 0).
, ()
.
. 50, :
assertTrue(rectangle.area() == 50). xUnit
assert() ().
,
assertEqualsO ,
. , ,
, assertEqualsO
. ,
160
III
, . ,
JUnit : assertEquals(50, rectangle.area()).
, , . ,
Contract, status,
Offered, Running.
, :
Contract contract= new Contract!): // Offered
contract.begin();
// Running
assertEquals(Running.class, contract.status.class):
status.
, status
. , status Running,
:
assertEquals(. . .. contract.startDataO): / / ,
// status Offered
, , ,
(public)
. JXUnit,
JUnit , ,
.
, . ,
- ,
,
.
, . ,
, .
, ,
, , ,
.
xUnit Smalltalk ( SUnit)
assert ,
, .
Java ,
Java ,
assert() .
, assert() ,
.
JUnit 1.
, ' True", false) ,
,
,
.
29 xUnit
161
: Assertion failed:
True. ,
.
, assert()
.
, ,
.
Fixture1 ()
,
?
- TestCase. setUp()
( ).
(
) , ? .
: ,
, ,
. , ,
. (
scaffolding , ).
. :
,
,
,
;
,
(
).
. '
assert(),
.
, , ,
, , ,
.
xUnit . ,
,
.
setUp().
, .
fixture
. . .
6 *. 297
162
III
, ,
, ,
. :
EmptyRectangleTest
public void testEmptyO {
Rectangle empty= new RectangleCO,0.0,0):
assertTrue(empty.isEmpty());
}
public void testWidthO {
Rectangle empty= new Rectangle(0,0,0.0):
assertEquals(0.0. empty.getWidthO, 0.0):
}
( assertEquals()
,
.) , :
EmptyRectangleTest
private Rectangle empty:
public void setUpO {
empty= new RectangleCO.0,0,0);
}
public void testEmptyO {
assertTrue(empty. isEmptyO):
}
public void testWidthO {
assertEquals(0.0. empty.getWidthO. 0.0);
}
. xUnit ,
setUp() TestCase
. ,
, ,
setUp() , .
?
.
setUpO, . , ,
, . ,
, ,
.
TestCase
xUnit.
TestCase.
,
, .
29 xUnit
163
,
(Rectangle), ,
, , NormalRectangleTest.
setUp(), Rectangle, . Rectangle
. ,
, TestCase.
,
() . (
).
. \ ,
. ,
- .
External Fixture ( )
?
tearDown() ,
.
,
, , . ,
, ,
, . :
testMethod(self):
file File("foobar").open()
try:
... ...
finally:
file.closeO
,
:
setUp(self):
s e l f . f i l e - File("foobar").open()
testMethod(self):
try:
... ...
finally:
self .file.closeO
-, finally
, - . -,
,
finally . ,
164
III
... ...
tear-Down (self):
self.file.closeO
Test Method ( )
? , test.
,
, ?
-
:
( Java , -, package);
;
.
, ,
.
, ,
. ,
, . ,
, .
xUnit ,
test.
(TestSuite).
, . ,
, JUnit,
testAssertPosInfinityNotEqualsNeglnfinity. ,
, , , ,
, assert() JUnit
. , JUnit,
, ,
29 xUnit
165
. (
).
. ,
, .
,
. , ,
(, ,
). , ,
.
(Patrick Logan) ,
. (McConnell)1,
(Caine) (Gordon)2:
(outlines) . .
,
, . :
/ * 3 * /
/ * * /
/ * */
,
. ,
:
/* */
/ * */
/ * * * * /
/ * * **/
/ * * * * /
/ * */
, - .
, .
.
, , ,
, ,
. ( - Java,
Eiffel.)
.
1
2
McConnell, Steve. 1993. Code Complete, chapter 4. Seattle, Washington: Microsoft Press.
Caine, S. H., Gordon, E. K. 1975. PDL: A Tool for Software Design, AFIPS Proceedings of the 1975
National Computer Conference.
tuple
. . .
166
III
Exception Test ( )
?
, ,
.
, , .
, .
:
public void testRateO {
exchange.addRate("USD". "GBP". 2);
i n t rate= exchange.findRate("USD". "GBP"):
assertEquals(2, rate);
'
}
.
:
public void testMissingRateO {
try {
exchange.findRate("USD". "GBP"):
failO:
} catch (IllegalArgumentException expected) {
}
}
findRate() ,
fail() xUnit, , .
, ,
findRate(). ,
- ( ) (
assert), .
All Tests ( )
? ,
,
(package) , .
, TestCase
. , ,
. (
TDD ,
, , , ,
.) ,
xUnit, IDE,
,
AIITests, suite(),
TestSuite. AIITests :
29 xLlnit
167
? ,
, ,
, , ,
, ,
1. ,
( ) ,
,
.
,
,
.
(design patterns)
, - 2.
Design Patterns ( ) ,
. ?
, ,
. TDD
.
.
, , .
.
:
1
2
Alexander Christopher. 1970. Noteson the Synthesis of Form. Cambridge* MA: Harvard University Press.
Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John. 1995. Design Patterns: Elements of
Reusable Object Oriented Software. Boston: Addisoh-Wesley. : ., .,
., . - .
. .: , 2001.
30
169
Command ()
, ;
Value Object (-)
, ,
(aliasing);
Null Object (-)
;
Template Method ( )
, ,
.
Pluggable Object ( )
;
Pluggable Selector ( )
;
Factory Method ( )
;
Imposter ()
;
Composite () ,
;
Collecting Parameter ( ) ,
, ,
, ,
.
. 30.1 , TDD
.
3 0 . 1 . ,
(TDD)
Command ()
/
/
Template Method ( )
/
/
Pluggable Object ( )
Pluggable Selector ( )
Factory Method ( )
Imposter ()
Composite ()
Collecting Parameter ( )
/
/
/
170
III
Command ()
,
, ? ,
, .
.
,
(,
).
.
, , ,
.
(, -),
, . ,
, .
, , ,
, .
,
.
.
.
, .
. ,
.
. ,
, run().
Runnable Java:
Runnable
interface Runnable
public abstract void run();
run() , .
, Java
Runnable ,
, ( -
Smalltalk/Ruby LISP).
30
171
.
- . ,
.
.
(, , - ,
).
, , (Rectangle).
, ,
. (, )
.
, .
, ,
! , ,
.
(aliasing).
, , ,
.
. -
, , .
.
, , ,
,
. Observer ().
, ,
, , . ,
, -
. Observer ()
, ,
.
,
. ,
. ? ,
. ,
. , ,
,
.
,
.
, , 1
Smalltalk. 2 1,
?
172
III
:- 2.
b := a.
:= a bitAt: 2 put: 1.
=> 6
b => 2
, . Small
talk
, .
,
. .
Value Object (-)
, .
, -.
( ). , -
.
,
:
, ,
, ,
.
Value Object (-) ,
, , . ,
, ,
,
. , Value Object (-)
- , ,
' .
- (
,
).
, , .
, ,
.
30 1 7 3
if (guard != null) {
guard.canWrite(path);
}
return fi1eSystem.setReadOnly(thi s);
}
- SecurityManager,
, LaxSecurity:
SecurityManager
public static SecurityManager getSecurityManagerO {
return security null ? new LaxSecurityO : security:
}
, -
null.
:
File
public boolean setReadOnlyO {
SecurityManager security - System.getSecurityManagerO;
security.canWrite(path);
return fileSystem.setReadOnly(this);
}
OOPSLA
(Erich Gamma) , Null Object (-)
JHotDraw.
, ,
,
. (
.)
Template Method ( )
,
? ,
.
174
I I I
:
;
;
.
.
-
. ,
.
, . ,
JUnit :
TestCase
30
175
,
.
, , ,
.
.
Pluggable Object ( )
?
:
if (circle) then {
. . .. circle ...
} else {
. . . . circle
}
. (circle)
,
,
, . .
TDD ,
.
,
, , -
: PluggableObject ( ).
.
. ,
. - -
, , ,
.
, ,
,
.
- , , ,
,
,
.
:
SelectionTool
Figure selected:
public void mouseDownO {
selected= findFigureO;
i f (selected ! null)
176
III
select(selected);
}
public void mouseMoveO {
if (selected != null)
move(selected):
else
mqveSelecti onRectangl e();
}
public void mouseUpO {
i f (selected == null)
selectAllO:
}
( ,
, ). , ?
, SelectionMode, : SingleSelection
MultipleSelection.
SelectionTool
SelectionMode mode:
public void mouseDownO {
selected= findFigureO;
i f (selected != null)
mode= SingleSelection(selected);
else
mode= MultipleSelectionO;
}
public void mouseMoveO {
mode. mouseMoveO;
}
public void mouseUpO {
mode.mouseUpO;
}
( ) .
Pluggable Selector1 (
)
?
.
Beck, . 1997. The Smalltalk Best Practice Patterns,
70-73. Englewood-Cliffs, NJ: Prentice-Hall.
, , (Phyllis Diller): ,
, , .
30
177
,
? ,
.
abstract class Report {
abstract void printO:
}
class HTMLReport extends Report {
void printO { ...
}
}
class XMLReport extends Report {
void printO { ...
}
}
: switch.
.
:
;
switch;
.
abstract class Report {
String printMessage;
Report(String printMessage) {
this.printMessage= printMessage;
}
void printO {
switch (printMessage) {
case "printHTML" :
printHTMLO:
break;
case "printXML" :
printXMLO:
break:
}
}:
void printHTMLO {
, }
void printXMLO {
}
'}
, ,
switch.
178
III
Pluggable Selector ( )
Reflection API:
void printO {
Method runMethod= getClassO,getMethod(printMessage. null):
runMethod.invokeCthis. new Class[0]):
}
-
, , ,
switch.
, .
.
,
: ,
.
Factory Method ( )
,
? ,
.
, .
, , , ,
. , Java,
.
. :
public void testMultiplicationO {
Dollar five= new Dollar(5):
assertEquals(new Oollar(lO), five.times(2)):
assertEquals(new Dollar(15). five.t1mes(3)):
}
Money,
, Dollar.
,
, .
assert :
public void testMultiplicationO {
Dollar five = Money.dollar(5):
assertEquals(new Dollar(lO). five.times(2));
assertEquals(new Dollar(15). five.times(3));
} ,
Money
static Dollar dollardnt amount) {
30
179
(Factory Method),
.
,
: , ,
, .
, ,
.
.
Imposter ()
? ,
, .
-
. , Pluggable
Selector ( ),
. ,
.
, .
, . ,
.
if
- , . ,
,
.
TDD, Imposter (
) , .
.
, . ,
:
testRectangleO {
Drawing d= new DrawingO:
d.addFigure(new RectangleFigureCO, 10. 50, 100)):
RecordingMedium brush= new RecordingMedlumO;
d.display(brush);
assertEqualsC'rectangle 0 10 50 100\n", brush.logO);
}
.
Imppster () : RectangleFigure
OvalFigure.
180
I I I
testOvaK) {
Drawing d= new DrawingO;
d.addFigure(new OvalFigure(0, 10, 50. 100));
RecordingMedium brush= new RecordingMediumO;
d.display(brush);
assertEqualsC'oval 0 10 50 100\n", brush.logO):
}
, Imposter (
) , .
, , Money
, Money. ,
, , .
Imposter ()
:
Null Object (-)
, ;
Composite ()
.
Imposter ()
, ,
.
Composite ()
,
? Imposter
() ,
, .
: Account () Transaction
().
Composite (), .
Transaction (,
,
):
Transaction
Transaction(Money^value) {
this.value= value:
}
Accout
Transaction:
Account
Transaction transactions!;]:
Money balanceO {
Money sum= Money.zeroO:
30
181
}
:
Transaction ;
Account .
. ,
. , :
OverallAccount,
Account. ! !
, Account Transaction
? Holding (),
- :
Holding
interface Holding
Money balanceO:
balanceO Transaction,
:
Transaction
Money balanceO {
return value;
}
Account , Holding:
Account
Holding holdings!!]:.
Money balanceO {
Vi
Money sum= Money.zeroO:
for (int i= 0; i < holdings.length: i++)
j sum= sum. pi us (hoi dings[i]. balanceO):
return sum:
}
, OverallAccount, .
OverallAccount Account,
, Account.
.
Composite ().
. ,
. ,
,
. ,
: (Folders),
(Folders), (TestSuites), -
182
III
(TestSuir.es), (Drawings),
(Drawings).
,
.
Composite
(), , ,
. , ,
,
,
-. ,
,
, Composite ()
, .
Collecting Parameter ( )
,
? ,
.
java.io.Externalizable. write- Ex
ternal ,
. ,
,
ObjectOutput, :
java.io.Externalizable
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException:
}
-
Composite (). JUnit
TestResult ,
.
- ,
,
. , ,
Expression . ,
, , , :
testSumPrintingO {
Sum sum= new Sum(Money.dollar(5), Money.franc(7));
assertEquals("5 USD + 7 CHF", sum.toStringO);
}
String toStringO {
return augend + " + " + addend;
}
30
183
, Expression
, :
testSumPrintingO {
Sum sum= new Sum(Money.do11ar(5). Money.franc(7));assertEquals("+\n\t5 USD\n\t7 CHF", sum.toStringO);
}
-,
:
String toStringO {
IndentingStream writer= new IndentingStreamO;
toString(writer);
return writer.contentsO:
}
void toStringdndentingWriter writer) {
writer.print1n("+");
writer. indentO;
augend.toString(writer):
writer.printlnO:
addend.toString(writer);
writer.exdentO:
}
Singleton ()
,
? .
,
.
.
TDD 1 .
.
TDD ,
. , TDD , ,
, .
. ,
.
,
, .
, .
, , TDD,
: ,
. ,
. ,
,
. : , ,
,
, . .
Reconcile Differences ( )
?
.
, .
Fowler, Martin. 1999. Refadoring: Improving the Design of Existing Code. Boston: Addison-Wesley.
: . . : . .: -, 2003.
31
185
. . ,
, , .
.
, ,
, , .
.
, ,
.
,
.
:
. ,
.
. ,
.
. ,
.
. ,
.
.
,
, . ,
,
, .
, , ,
. ,
?
.
,
. .
Isolate Change ( )
,
? .
:
, , , .
.
,
186
III
,
.
, , ,
, ,
. , ,
findRate()
, findRate() .
findRate() .
.
, , ,
, .
.
Extract Method ( ),
Extract Object ( ) Method Object (
).
Migrate Data ( )
?
.
.
,
.
1. .
2. ,
.
3. ,
.
4. .
5. ,
.
API.
:
1. .
2.
, .
3. .
4. .
5. .
31
187
,
One to Many ( ). ,
TestSuite, One to Many ( ).
:
def testSuite(self):
suite= TestSuiteO
sui te.add(WasRunC"testMethod"))
suite.run(self.result)
assertC'l run. 0 failed" == self.result.summaryO)
, test:
class TestSuite:
def add(self. test):
self.test= test
def run(self. result):
self.test.run(result)
.
:
TestSuite
def i n i t (self):
self.tests [ ]
, test,
:
TestSuite
def add(self, test):
self.test- test
self.tests.append(test)
.
, ( ),
.
TestSuite
def run(self. result):
for test in self.tests:
test.run(result)
test:
TestSuite
def add(self. test):
self.tests.append(test)
, , ,
Java, Vector/Enumerator Collection/Iterator.
188
III
Extract Method ( )
?
.
. . ,
.
, :
1. , .
, ,
.
2. ,
, ,
.
3. . .
4. ,
, .
5. ,
.
Extract Method ( ),
. , . .
? ,
, ,
, - .
, ,
, .
. ( Smalltalk
Refactoring Browser :
, , , ,
,
, .)
. , , Inline Method (
), ,
.
31
189
Inline Method ( )
,
?
.
1. .
2. .
3. . ,
, reader.getNext(), ,
,
.
, ,
, Bank
Expression Money.
public void testSimpleAdditionO {
Money five= Money.dollar(5):
Expression sum= f i v e . p l u s ( f i v e ) ;
Bank bank= new BankO;
Money reduced= bank.reduce(sum, "USD"):
assertEquals(Money.dollar(10). reduced);
}
.
Money? , . ?
Bank.reduce() , :
public void testSimpleAdditionO {
Money five= Money.dollar(5);
Expression sum= f i v e . p l u s ( f i v e ) ;
Bank bank= new BankO;
Money reduced= sum.reduce(bank, "USD");
assertEquals(Money.dollar(10), reduced);
}
, , , .
, Inline Method ( )
.
,
,
. , ,
, .
190
III
,
. ( , .)
, Inline Method ( ) ,
, : ,
, ... , ?
, .
, .
Extract Interface ( )
Java?
, .
1. .
.
.
2. ,
.
3. .
.
4. , , .
,
. , Rectangle (
), Oval ()
Shape (). ,
, . ,
.
, ,
Crash Test Dummy ( )
(Mock Object).
, .
IFile, File.
,
, ? , File,
DiskFile,
, , , .
31
191
Move Method ( )
,
? , ,
.
1. .
2. . .
.
3. ,
,
.
- ,
. -
,
.
4. .
,
. ,
.
Shape ():
Shape
int width= bounds, right - bounds. l e f t O ;
int height bounds.bottom() - bounds.top();
int area= width * height;
, , , ,
,
. , ,
Shape, bounds (
Rectangle). Rectangle:
Rectangle
public int areaO {
int width= this.righto - this.leftO;
int height= this.bottomO - this.topO:
return width * height:
}
'
192
I I I
Shape
i n t area- bounds.area():
Move Method ( )
:
,
.
, , ,
.
.
. Rectangle
... ! .
.
.
, ,
. .
Method Object ( )
,
?
.
1. ,
.
2.
.
3. run().
, .
4. run()
.
-
. , ,
,
. -,
31
193
.
.
.
- ,
Extract Method ( ).
,
, ,
,
.
, ,
. -
,
, - .
Add Parameter ( )
?
1. ,
.
2. .
3. ,
, ,
.
.
.
, ,
,
.
. ,
,
.
194
III
1. .
2. ,
.
3. .
4. parameter this.parameter.
5. ,
.
6. this.
7. .
, API,
( ). , , ,
.
TDD
,
, TDD
. ,
. ,
, ,
.
?
:
?
?
,
. ,
,
. ?
, .
TDD , .
.
, .
,
. .
,
. 20
,
.
196
III
, .
, 20 ,
. , .
, ,
.
, , .
Refactoring
Browser for Smalltalk -
. Java
. , ,
.
?
(Phlip) ,
: , .
, .
, ,
. :
;
;
;
.
, . ,
.
( : )
.
?
() ,
,
?
, ,
.
, ,
:
.
, assert(), ,
- . ,
.
32 TDD
197
.
, ,
, .
. TDD
, , . ,
,
. , - , ,
. :
, ,
.
. , ,
. (
, 9,8 /2.
10 ,
, 10 .)
.
, ,
.
,
.
, .
TDD
?
(framework) ,
.
TDD .
: ,
.
:
, (code for today, design for tomorrow).
, TDD :
, (code for tomorrow, design for
today). :
.
,
.
,
. -
198
III
.
( , ).
,
. , ,
, ,
, .
.
/ (Open/Closed Principle1), ,
, .
, TDD
,
. , TDD ,
,
.
, ,
( ).
,
?
, .
/ (Open/Closed Principle)
, ,
, , , .
, , TDD
.
. ,
, , . ,
, . .
TDD,
, ,
.
?
? :
, .
:
- , ,
,
, - (
, ). . .
32 TDD
199
1 , ;
2 , ;
3 , .
(
), .
! ( , Small
talk, ).
(
! ! ' ).
, (Bob Binder) Testing
Object- Oriented Systems1 ( - )
65 . ?
, .
,
(MTBF, Mean Time Between Failures).
, Smalltalk ,
32- . ,
, .
, MAXINT. ,
, ,
.
,
? MTBF ?
,
, ,
, .
? ,
MTBF. ,
MTBF 10 100 , ,
(,
, - ,
).
TDD . TDD
. ,
.
- , ,
. ( -,
) . ,
:
. ,
TDD.
1
Binder, Bob. 1999. Testing Object-Oiiented Systems: Models, Patterns, and Tools. Boston: Addison-Wesle
.
200
I I I
TriangleTest
testEquilateral
self assert: (self evaluate: 2 side: 2 side: 2) = 1
testlsosceles
self assert: (self evaluate: 1 side: 2 side: 2) = 2
testScalene
self assert: (self evaluate: 2 side: 3 side: 4) = 3
testlrrational
[ s e l f evaluate: 1 side: 2 side: 3]
on: Exception
?
, ,
, ?
.
. ,
.
. ,
,
, .
32 TDD
201
, ,
, ,
.
TDD?
TDD Smalltalk Refactoring
Browser. C++ vi.
.
, TDD
(),
:
;
.
, ,
?
, TDD, ]
.
, ,
?
TDD
?
TDD
? ?
?
,
TDD, , LifeWare (www.lifeware.ch). 4 .
40 -.
250 000 250 000 (
Smalltalk).
4000 , 20 .
.
, , TDD.
,
,
.
202
III
?
,
( unit tests,
), :
, ,
, .
, , , ,
.
, (appli
cation-level tests).
( ).
, .
,
(ATDD, Application Test-Driven Development).
.
, ? ,
. ,
, , ,
.
. (
, )
: .
,
,
.
.
, ,
,
.
TDD
. , TDD
. ,
.
,
, .
One Step Test (
).
, TDD.
ATDD:
. ,
, , -
32 TDD
203
. TDD
, :
;
.
TDD
?
, ,
.
TDD. ?
TDD
( ).
.
, ,
, , .
,
, .
. , (
), ,
, , .
. .
. ?
, , :
.
,
.
, .
. , ,
,
. ,
, , ,
, .
-, . ,
, .
,
. , ,
.
, ,
. ,
204
III
, ,
, TDD.
.
TDD?
. TDD .
, - , ,
,
, TDD . TDD -
, ,
. TDD
.
,
.
, , , , .
, ,
. , 20 % .
, , 100 %
, .
, 80 % ,
.
TDD .
,
TDD ,
. ,
, TDD .
TDD ,
. ,
,
, , ,
. , ,
,
. TDD
. (
), ,
, . ,
.
,
, , TDD
.
32 TDD
205
TDD
?
, ,
.
. ,
, , ,
, .
/ ,
? - ,
, ?
TDD ,
? ( :
, ,
2 000 000
.)
TDD
?
,
, .
, , ,
, , , , .
, ,
, .
(, ! ,
, , )
. , ,
, .
? , ,
, 6 9, 6 ( 9 ).
, , ,
,
.
, , ,
.
,
. , ,
.
,
, , -
206
III
,
.
, Smalltalk Best Practice
Patterns ( Smalltalk). -
, .
, ,
, .
, ,
.
.
TDD : TDD
, . ,
Strategy
(). , .
, ,
Strategy ().
(Robert Martin) TDD.
, . ,
,
.
. , , -,
, , .
TDD ?
. , TDD
,
. ( ,
, ,
.) ?
.
, .
( -')-
. TDD,
.
TDD, . paMars Lander , 3 1999 .
1999 . ,
, - .
120 , -
. . .
32 TDD
207
, .
. .
,
. .
,
, .
. ,
? ?
. ,
TDD
, .
TDD , .
TDD ,
,
.
.
, , TDD
.
TDD,
, ,
. TDD
.
, ,
. , API
, , , ,
, .
,
, ,
.
, TDD ?,
. (Phlip) :
,
, .
,
, ,
().
, .
, ;
, .
, (
, , ,
). ,
, .
208
III
?
: Test-Driven Development .
,
.
Development ()
,
,
. TDD
, ,
, , , ,
.
Driven ( ) TDD test-first pro
gramming ( ).
fist () last ( ).
,
. .
,
, ,
. (
,
, .)
, ? ? ?
? ( ,
).
Test () ,
. , . TDD
, .
, ,
, .
TDD
?
, ,
, TDD,
, (eXtreme Programming)
. , TDD,
? ,
TDD,
, TDD
:
32 TDD
209
. , TDD,
,
. ,
,
. , ,
.
TDD. :
, ,
, . TDD
, ,
. ,
.
. ,
, , .
, , .
(Bob Martin) 1
.
, , ,
.
. ,
.
, , ,
. 15-30 .
.
(Bill Wake): 2 ,
1.
. TDD , , , ,
, ,
' .
,
.
.
. .
,
,
. ,
1
210
III
. .
.
. TDD MTBF
( ), ,
. (Gareth Ree
ves) -
.
,
, ,
,
. , ,
, ,
.
TDD
(Darach Ennis) TDD,
TDD. :
TDD, . ,
TDD. :
GUI (,
Swing, CGI, JSP/Seivlets/Struts);
(, RPC, Messaging, C0RBA/EJB J MS);
TDD (,
JDBC);
,
, ,
;
TDD /
.
, , , .
TDD.
(Martin Fowler)
, ,
, ,
TDD. , (Ralph Beattie) .
,
. ,
- , . ,
, , ,
, .
, - .
, , ,
:
, . TDD
.
TDD,
. , ,
. ,
, .
. ,
, .
,
.
.
: .
Ruby,
. , ,
,
, .
Java,
Ruby. , ,
, ,
.
212
III
, , .
,
. , , ,
, , TDD,
.
.
,
. ,
. ,
:
. ,
. ,
, .
,
.
,
, ,
,
. ,
.
. , (TDD),
,
,
.
,
.
, . , , . ,
, , .
, . ,
, ,
. ,
, , .
I
.
Quality Software
Management (Gerald Weinberg), , 1:
Systems Thinking^. ,
.
:
2 .
,
. ,
,
.
, .
,
, ,
.
. . 1.1-1.3
.
. 1 . 1 . , , ,
1
2
Weinberg, Gerald. 1992. Systems Thinking. Quality Software Management. New York: Dorset House.
, ,
. . .
214
. 1.2. ,
1.3. ,
, . , .
, .
,
, ,
.
.
. ,
.
, .
. 1.4.
. 1.4.
.
,
. ,
.
, ,
. . 1.4 :
215
, ,
- .
.
, ,
.
:
,
;
,
,
;
,
.
,
,
,
. . 1.5 ,
.
-
*
. 1.5.
, ,
, , ,
.
(, ),
, .
, ,
, :
.
,
,
,
.
216
,
,
.
, ,
.
II
, ,
TDD. ,
, TDD. ,
,
TDD.
, . ,
, ,
TDD, , ,
.
, fib(O) = 0. .
public void testFibonacciO {
assertEqualsCO. fib(O)):
}
int fibdnt n) {
return 0;
}
( TestCase ,
.)
, fib(l) = 1.
public void testFibonacciO {
assertEqualsCO. f i b ( 0 ) ) ;
' assertEqualsd, f i b ( D ) :
}
assert() ,
testFibonacciOfOnelsOne.
,
. 0, :
int fib(int n) {
i f (n = 0) return 0;
return 1;
}
218
II
.
,
. assert(),
fib():
public void testFibonacciO {
i n t cases[][]- { { 0 . 0 } . { 1 . 1 } } :
for ( i n t i= 0: i < cases.length; i++)
assertEquals(cases[i][l]. f i b ( c a s e s [ i ] [ 0 ] ) ) :
}
:
public void testFibonacciO {
i n t c a s e s [ ] [ > {{0.0} .{1.1} .{2.1}}:
for ( i n t i= 0; i < cases.length; i++)
assertEquals(cases[i][l], f i b ( c a s e s [ i ] [ 0 ] ) ) :
}
, . ,
1 2.
:
public void testFibonacciO {
i n t cases[][]= { { 0 . 0 } . { 1 . 1 } . { 2 . 1 } . { 3 . 2 } } :
for ( i n t i= 0; i < cases.length; i++)
assertEquals(cases[i][l]. f i b ( c a s e s [ i ] [ 0 ] ) ) :
}
! - . (
, ):
i n t f i b ( i n t n) {
i f (n == 0) return 0:
i f (n <= 2) return 1;
return 2:
}
. 2,
1 + 1.
i n t f i b d n t n) {
i f (n == 0) return 0;
i f (n <= 2) return 1;
return 1 + 1;
}'
fib(n-l):
i n t f i b ( i n t n) {
i f (n == 0) return 0;
i f (n <= 2) return 1;
return f i b ( n - l ) + 1 ;
}
219
fib(n-2):
int fibCint n) {
if (n == 0) return 0;
if (n <= 2) return 1:
return fib(n-l) + fib(n-2):
}
.
fib(2), :
int fibCint n) {
if (n == 0) return 0:
if (n == 1) return 1:
return fib(n-l) + fib(n-2);
}
,
TDD.
Account, , 180
Add Parameter, , 193
add, , 119
addend, 72
aliasing, , 171
All Tests, , 166
AllTests, , 166
application-level test, 202
assert, 132
Assert First, assert, 132
assert, , 159
assertEquals, 159
assertion, 159
ATDD, Application Test-Driven Development, 202
augend, 72
Bank, , 69
Break, , 141
Broken Test, , 151
D
Design Patterns, , 168
Do over, , 143
Dollar, , 17
, 24
, 50
, 30
Franc, 47
, 63
equals, , 33
, 42
, 47
Evident Data, , 135
Exception Test, , 166
Explanation Test, , 139
Expression, , 67
External Fixture, , 163
Externalizable, , 182
Extract Interface, , 190
Extract Method, , 102, 188
F
Factory Method
, 50
Factory Method, , 178
fail, , 166
Fake It, , 31, 153
File, Java, 172
Fixture, , 161
framework, , 197
Franc,
, 40
, , 50
, 39
Dollar, 47
equals, 45
, 63
I
Imposter, , 67, 179
Inline Method, , 189
Isolate Change, , 185
Isolated Test, , 128
J
java.io.Externalizable, , 182
java.io.File, , 172
Jester, 94
JHotDraw, 173
J Probe, 94
JUnit, 124, 160
_--
, 91
JXUnit, 160
L
LaxSecurity, , 173
UfeWare, 201
Log String, -, 149
N
None, , 99
Null Object, -, 172
Observer,
, 149
Obvious Implementation,
, 31, 156
One Step Test, , 136
One to Many, , 157
Open/Closed Principle, 198
Pair, , 78
pass, , 99
Pluggable Object, , 175
Pluggable Selector,
, 176
Python, 97
R
Realistic Data, , 134
Reconcile Differences,
, 184
221'
reduce, , 68
Reflection API, 178
Regression Test, , 141
Runnable, , 170
s
scaffolding, 161
Self Shunt, , 147
self, , 122
setUp, , 104, 161
Shower Methodology, , 142
SmallLint for Smalltalk, 90
Starter Test, , 137
suite, , 166
Sum, , 68
, 72
, 72
summary, , 113
SUnit, Smalltalk Unit, 160
T
TDD
, 201
, 195
, 195
, 204
, 90
, 89
, 203
, 201
, 11
, 195
, 205
, 205
, 203
, 210
, 40
, 208
, 37
, 208
, 56
, 206
, 85
tearDown, , 108, 163
Template Method, , 173
Test Data, , 134
Test First, , 131
test infected, 13
Test List, , 129
Test Method, , 164
Test, , 124
test, , 164
TestCase, , 101
Test-Driven Development
, 208
222
testFailed, , 115
test-first programming, 208
TestResult, , 113
testStarted, , 115
TestSuite, , 118, 166, 187
times, , 24
, 49, 58
toString, , 60
Transaction, , 180
Triangulate, , 155
Triangulation, , 33
v-w
Value Object, -, 32, 170
WasRun, , 99
WyCash, 17
-
, 85
, 146
, 68
, 67
, 91
, 53
, 68
, 76
, 81
, 61
, 67
, , 90
, 131
,475
, 176
, 189
, 190
, 102, 188, 220
, 67, 90
, 183
, 175
, 186
, 134
, 89
, 94
, 206
, 141
, 213
, 214
, 193
, 66
, 71
, 81
,47
, 26
-
, 108, 149
, 89
, 90
, 26
, 196
, 23
; 185
, 128
, 139
, 60
, 151
, 190
, 197
, 150
, 112
, 166
, 93, 196
, 163
, 92
,92
, 44, 60
, 170
, 118, 180
, 178
, 140
, 24
, , 90
, 68
, 77
TDD, 144
, 90
, 189
, 188
, 191
, 192
, 68
, 164
, 178
, 173
, 192
, 142
, 186
, 22
, 118, 166
, 119
, 171
, 205
, 137
-, 172
, 149
, 214
, 175
-, 172
, 171
, 178
, 161
-, 32, 170
, 139
, 139
, 139
, 183
, 157
, 143
, 31, 156
, 77, 193
, 182
, 193
, 209
, 168, 205
Ail Tests, 166
Another Test, 140
Assert First, 132
Break, 141
Broken Test, 151
Cheap Desk, Nice Chair, 144
Child Test, 145
Clean Check-in, 151
Collecting Parameter, 119, 182
Command, 170
Composite, 118, 180
Crush Test Dummy, 149
Do over, 143
Evident Data, 135
Exception Test, 166
Explanation Test, 139
External Fixture, 163
Factory Method, 178
v
Fake It, 31, 153
Fixture, 161
Imposter, 179
Isolated Test, 128
Learning Test, 139
Log String, 149
Mock Object, 146
Null Object, 172
Obvious Implementation, 31, 156
One Step Test, 136
One to Many, 157
Pluggable Object, 175
Pluggable Selector, 176
Realistic Data, 134
Regression Test, 141
Self Shunt, 147
Singleton, 183
Starter Test, 137
Template Method, 173
Test First, 131
Test List, 129
Test Method, 164
Triangulate, 155
Triangulation, 33
Value Object, 32, 170
, 168
TDD, 205
, 191
, 141
, 31, 153
, 146
, 63
, 53
, 94
223
224
, 149
/, 198
, 209
, 32
, 134
, 141
, 163
, 89
xUnit, 123
, 184, 209
Add Parameter, 193
Extract Interface, 190
Extract Method, 102, 188, 220
Inline Method, 189
Isolate Change, 185
Method Object, 192
Method Parameter to Constructor Param, 193
Migrate Data, 186
Move Method, 191
Reconcile Differences, 184
, 196
, 109
, 67, 179
, 147
, 81
, 133
, 23, 129
, 66
, 165
, 129
, 201
, 165
, 126
, 126
, 105
, 131
, 137
, 136
, 134
, 139
, 145
, 166
, 105, 128
, 164
, 93, 196
, 94, 198
()
, 39
, 202
, 118
, 36
, 129
, 136
, 112
, 205
, 145
, 141
, 98
, 151
, 129
, 200
' , 202
, 126
, 146
, 27
, 203
, 166
, 196
, 145
, 139
, 164
, 196
, 198
, 33, 155
, 175
, 50, 178
, 217
, 161
, 163
, 104
, 76
, 81
, 39
,47
, 39
-
, 78
, 92
, 209
, 210
, 173
, 137