-
Notifications
You must be signed in to change notification settings - Fork 187
Expand file tree
/
Copy pathtestrun.html
More file actions
329 lines (279 loc) · 9.86 KB
/
testrun.html
File metadata and controls
329 lines (279 loc) · 9.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<!-- Begin utPLSQL Body -->
<!-- $Id$ -->
<h1>A "Test Run" with utPLSQL</h1>
<p>
<a name="Testrun"></a>I will put utPLSQL to work in a small-scale development
effort, to show you how it all hangs together. I've got a "hangnail" in
my PL/SQL development work, called SUBSTR. This function bothers me and
I want to take care of it. What's the problem? SUBSTR is great when you
know the starting location of a string and number of characters you want. In
many situations, though, I have the start and end locations and I need
to figure out the number of characters I then want. Is it:
</p>
<pre>
mystring := SUBSTR (full_string, 5, 17); -- start and end? Nah...
mystring := SUBSTR (full_string, 5, 12); -- end - start?
mystring := SUBSTR (full_string, 5, 13); -- end - start + 1?
mystring := SUBSTR (full_string, 5, 11); -- end - start 1 1?
</pre>
<p>
Why should I have to remember stuff like this? I
never do, and so I take out a scrap of paper, write down 'abcdefgh', put
a mark over the "c" and another over the "g", count on my fingers and then
remember that of course the formula is "end - start + 1".
</p>
<p>
All right, so I did that a dozen times, I am sick
of it and determined to stop wasting my time in the future. I will write
a function called "str.betwn" (the betwn function defined in the str package)
that does the work and the remembering for me.
</p>
<p>
Instead of immediately coding the function, however,
I will first write my unit tests with utPLSQL! Since my source package
is named "str", I will create a test package named "ut_str". I am a lazy
fellow, so I will take the lazy way out and generate the starting point
for my package:
</p>
<pre>
SQL> exec <a href="utgen.html">utgen.testpkg</a> ('str', output_type_in => utplsql.c_file)
</pre>
<p>
Note: for the above call to work, I must have already
set my default directory for utPLSQL, which I do via a SQL*Plus login script
that looks like this:
</p>
<pre>
exec utplsql.setdir ('e:\utplsql\test')
SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
</pre>
<p>
Otherwise, I would need to specify the directory
in my call to genpkg, as in:
</p>
<pre>
SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file, dir_in => 'e:\utplsql\test')
</pre>
<p>I then will find this package spec in the ut_str.pks file:</p>
<pre>
CREATE OR REPLACE PACKAGE ut_str
IS
PROCEDURE ut_setup;
PROCEDURE ut_teardown;
-- For each program to test...
PROCEDURE ut_betwn;
END ut_str;
/
</pre>
<p>
And I don't really have to modify the specification
at all. The body will, on the other hand, require some work, since I haven't
yet figured out a way to automatically generate the test code itself. Here
is the purely <a href="utgen.html">generated</a> test package body found
in the ut_str.pkb file:
</p>
<pre>
CREATE OR REPLACE PACKAGE BODY ut_str
IS
PROCEDURE ut_setup
IS
BEGIN
NULL;
END;
PROCEDURE ut_teardown
IS
BEGIN
NULL;
END;
-- For each program to test...
PROCEDURE ut_betwn
IS
BEGIN
utAssert.this (
'Test of betwn',
<boolean expression>,
);
END;
END ut_str;
/
</pre>
<p>
The setup and teardown procedures are fine (I don't
have any special setup and therefore teardown requirements), but the ut_betwn
needs lots of work. It doesn't really test anything yet.
</p>
<p>
Before I start writing my test code, however, I
will just sit back and think about what I want to test. Here are some inputs
that I can think of:
</p>
<table cellpadding="0" border="BORDER" cellspacing="0">
<tr>
<td valign="top">String</td>
<td valign="top">Start</td>
<td valign="top">End</td>
<td valign="top">Expected Result</td>
</tr>
<tr>
<td valign="top">"this is a string"</td>
<td valign="top">3 (positive number)</td>
<td valign="top">7 (bigger positive number)</td>
<td valign="top">"is is"</td>
</tr>
<tr>
<td valign="top">"this is a string"</td>
<td valign="top">-3 (invalid negative number)</td>
<td valign="top">7 (bigger positive number)</td>
<td valign="top">"ing" (consistent with SUBSTR behavior)</td>
</tr>
<tr>
<td valign="top">"this is a string"</td>
<td valign="top">3 (positive number)</td>
<td valign="top">1 (smaller positive number)</td>
<td valign="top">NULL</td>
</tr>
</table>
<p>
We could easily come up with a whole lot more test
cases - and if this was real life and not product documentation, I would
not move forward until I had identified all interesting tests. So let's
suppose I have done that and now I am ready to do some coding. Since I
am testing a function, I will want to compare the result of the function
call to my expected results. I will therefore change my assertion from
the generic "assert this" procedure to the utAssert.eq program, and put
the call to the function right into the assertion routine. Here, then,
is my first crack at transforming my ut_betwn procedure:
</p>
<pre>
PROCEDURE ut_betwn IS
BEGIN
utAssert.eq (
'Test of betwn',
str.betwn ('this is a string', 3, 7),
'is is'
);
END;
</pre>
<p>
Following the Extreme Programming philosophy ("code
a little, test a lot"), I will test this test case before I add all the
other test cases. I do this with a very simple call:
</p>
<pre>
SQL> exec utplsql.test ('str')
> SSSS U U CCC CCC EEEEEEE SSSS SSSS
> S S U U C C C C E S S S S
> S U U C C C C E S S
> S U U C C E S S
> SSSS U U C C EEEE SSSS SSSS
> S U U C C E S S
> S U U C C C C E S S
> S S U U C C C C E S S S S
> SSSS UUU CCC CCC EEEEEEE SSSS SSSS
>SUCCESS: "str"
</pre>
<p>
Now, you could say: "Great it worked!" Or you could
say: "I have no idea if it worked. Maybe it <i>always</i> says success."
I go for the latter, so let's deliberately cause a failure:
</p>
<pre>
PROCEDURE ut_betwn IS
BEGIN
utAssert.eq (
'Test of betwn',
str.betwn ('this is a string', 3, 7),
'this is a pipe'
);
END;
</pre>
<p>
Saving the file (but not bothering to recompile,
since utPLSQL will do it for me <a href="utconfig.html#Autocompile">automagically</a>),
I then run my test again:
</p>
<pre>
SQL> exec utplsql.test ('str', recompile_in=>false)
> FFFFFFF AA III L U U RRRRR EEEEEEE
> F A A I L U U R R E
> F A A I L U U R R E
> F A A I L U U R R E
> FFFF A A I L U U RRRRRR EEEE
> F AAAAAAAA I L U U R R E
> F A A I L U U R R E
> F A A I L U U R R E
> F A A III LLLLLLL UUU R R EEEEEEE
FAILURE: "str"
BETWN: Typical Valid Usage; expected "is is", got "this is a pipe"
</pre>
<p>
Now I have a higher degree of confidence that I
am getting this right. Excellent! Now I will add the other test cases:
</p>
<pre>
PROCEDURE ut_betwn IS
BEGIN
utAssert.eq (
'Typical Valid Usage',
str.betwn ('this is a string', 3, 7),
'is is'
);
utAssert.eq (
'Test Negative Start',
str.betwn ('this is a string', -3, 7),
'ing'
);
utAssert.isNULL (
'Start bigger than end',
str.betwn ('this is a string', 3, 1)
);
END;
</pre>
<p>
I will deliberately cause each of these tests to
fail, to give you a sense of the quality of feedback:
</p>
<pre>
> FFFFFFF AA III L U U RRRRR EEEEEEE
> F A A I L U U R R E
> F A A I L U U R R E
> F A A I L U U R R E
> FFFF A A I L U U RRRRRR EEEE
> F AAAAAAAA I L U U R R E
> F A A I L U U R R E
> F A A I L U U R R E
> F A A III LLLLLLL UUU R R EEEEEEE
FAILURE: "str"
betwn: Typical Valid Usage; expected "is is", got "this is a pipe"
betwn: Test Negative Start; expected "ing", got "BRRRING"
betwn: IS NOT NULL: Start bigger than end
</pre>
<p>
Faced with these results, I can zoom in on the code
within str.betwn that is causing these incorrect results. I resist the
temptation to fix the code for all my tests all at once. Instead, I make
one change at a time, then run my test again. I do that over and over again
until the failure for the single test case goes away. Then I move to the
next one. Eventually, I get a green light and am highly confident of my
program - if, of course, I really did come up with an exhaustive list of
tests.
</p>
<p>
As I think of another test case, I add a call to
utAssert to run that test.
</p>
<p>
As a bug is reported to me, I add a call to utAssert
to reproduce that bug. Then I repair my code.
</p>
<!-- End utPLSQL Body -->
</body>
</html>