11
11
<para ><emphasis >忘记Web吧:</emphasis ></para >
12
12
13
13
<para >我们要开发出一套Web应用,但首先要忘掉Web。这看似矛盾,却正是MVC的要求和精髓。
14
- 即对核心算法进行抽象,先实现Model,之后再去考虑Controller(控制器)和View(Web展现)。</para >
14
+ 即对核心算法进行抽象,先实现 <literal >Model</literal >,之后再去考虑
15
+ <literal >Controller</literal >(控制器)和
16
+ <literal >View</literal >(Web展现)。</para >
15
17
16
18
<para ><emphasis >忘记详细设计吧:</emphasis ></para >
17
19
36
38
37
39
<para >Subversion路径授权中,用户对象(用户/别名/组)显然是最重要的基本单位,
38
40
每一条授权策略都包含一个用户对象。那么我们第一个迭代就实现用户对象:
39
- User类,Alias类,Group类。</para >
41
+ <classname >User</classname > 类,<classname >Alias</classname > 类,
42
+ <classname >Group</classname > 类。</para >
40
43
41
- <para >假设svnauthz的 User, Alias, Group 类已经完成,我们期望他们实现的功能是什么呢?
42
- 于是在纸上写下假想任务目标(模拟python交互式命令行):</para >
44
+ <para >假设 <package >svnauthz</package > 的 <classname >User</classname >,
45
+ <classname >Alias</classname >, <classname >Group</classname > 类已经完成,
46
+ 我们期望他们实现的功能是什么呢?于是在纸上写下假想任务目标(模拟python交互式命令行):</para >
43
47
44
48
<programlisting >
45
49
>>> <emphasis >from svnauthz import User, Group, Alias</emphasis >
@@ -125,7 +129,7 @@ ImportError: No module named svnauthz
125
129
<sect3 id =" psm.tdd.iter1.unittest.pass" >
126
130
<title >编写模组,使测试用例通过</title >
127
131
128
- <para >之前执行测试用例失败,报告:找不到 svnauthz 模组。因为模组还没有创建,当然找不到了。
132
+ <para >之前执行测试用例失败,报告:找不到 < classname > svnauthz</ classname > 模组。因为模组还没有创建,当然找不到了。
129
133
于是创建一个空的模组文件 <filename >svnauthz.py</filename >。</para >
130
134
131
135
<screen >
@@ -147,10 +151,11 @@ NameError: global name 'User' is not defined
147
151
...
148
152
</screen >
149
153
150
- <para >太棒了,我们前进了一步,因为失败的原因已经不同了。错误报告说:User类未定义。
151
- 于是我们写一些代码,让测试用例通过。</para >
154
+ <para >太棒了,我们前进了一步,因为失败的原因已经不同了。错误报告说:
155
+ <classname >User</classname >类未定义。于是我们写一些代码,
156
+ 让测试用例通过。</para >
152
157
153
- <para >svnauthz.py第一个版本的代码如下 :</para >
158
+ <para >< filename > svnauthz.py</ filename > 第一个版本的代码如下 :</para >
154
159
155
160
<programlisting ><![CDATA[
156
161
1 #!/usr/bin/env python
@@ -193,25 +198,25 @@ NameError: global name 'Alias' is not defined
193
198
...
194
199
</screen >
195
200
196
- <para >好的,我们已经有一个测试用例(testUser)通过了!其他的测试用例呢?
197
- 先把他们注释掉,以便提前感受一下完全通过测试的滋味。</para >
201
+ <para >好的,我们已经有一个测试用例(< classname > testUser</ classname > )通过了!
202
+ 其他的测试用例呢? 先把他们注释掉,以便提前感受一下完全通过测试的滋味。</para >
198
203
199
204
<para >注意:我所说的注释掉不是删除代码,也不是把每一行变为注释,
200
205
而是非常简单的将暂不考虑的测试用例改名。</para >
201
206
202
207
<itemizedlist >
203
208
<listitem >
204
- <para >将 def testAlias(self) 改为 def _testAlias(self)</para >
209
+ <para >将 < code > def testAlias(self)</ code > 改为 < code > def _testAlias(self)</ code > </para >
205
210
</listitem >
206
211
207
212
<listitem >
208
- <para >将 def testGroup(self) 改为 def _testGroup(self)</para >
213
+ <para >将 < code > def testGroup(self)</ code > 改为 < code > def _testGroup(self)</ code > </para >
209
214
</listitem >
210
215
211
216
</itemizedlist >
212
217
213
218
<note >
214
- <para >注:只要不是以 test 开头都好。</para >
219
+ <para >注:只要不是以 < literal > test</ literal > 开头都好。</para >
215
220
</note >
216
221
217
222
<para >再次执行测试用例,太棒了完全通过!</para >
232
237
<sect3 id =" psm.tdd.iter1.code.coverage" >
233
238
<title >完善测试用例</title >
234
239
235
- <para >检查代码覆盖度,在Python下有coverage包可用。用easy_install安装之后,
236
- 就可以使用coverage命令了。</para >
240
+ <para >检查代码覆盖度,在 Python 下有 <package >coverage</package > 包可用。
241
+ 用 <command >easy_install</command > 安装之后,
242
+ 就可以使用 <command >coverage</command > 命令了。</para >
237
243
238
244
<screen >
239
245
$ <emphasis >coverage -x test_svnauthz.py</emphasis >
@@ -250,18 +256,19 @@ Name Stmts Exec Cover Missing
250
256
svnauthz 8 7 87% 15
251
257
</screen >
252
258
253
- <para >哦,看来我们离完美还是差了一点。从coverage的输出中可以看出,
254
- 我们的测试用例并没有对svnauthz.py的代码测试完全:第15行没有测试到。
255
- 也就是用空的用户名创建User对象,应该抛出异常。</para >
259
+ <para >哦,看来我们离完美还是差了一点。从 <command >coverage</command >
260
+ 的输出中可以看出,我们的测试用例并没有对 <filename >svnauthz.py</filename >
261
+ 的代码测试完全:第15行没有测试到。也就是用<emphasis >空的用户名</emphasis >创建
262
+ <classname >User</classname > 对象,应该抛出异常。</para >
256
263
257
- <para >我们在testUser用例的最后补充一条断言 :</para >
264
+ <para >我们在 < methodname >testUser</ methodname > 用例的最后补充一条断言 :</para >
258
265
259
266
<programlisting >
260
267
def testUser(self):
261
268
user1 = User('Tom')
262
269
self.assert_(str(user1) == 'Tom')
263
- self.assertRaises(Exception, User, " ")
264
- </programlisting >
270
+ < emphasis > self.assertRaises(Exception, User, " ")</ emphasis >
271
+ </programlisting >
265
272
266
273
<para >再次检查一下测试用例对代码的覆盖度。哇,100% 通过!</para >
267
274
@@ -282,10 +289,11 @@ svnauthz 8 8 100%
282
289
283
290
<!-- =============================================================== -->
284
291
<sect3 id =" psm.tdd.iter1.nosetests" >
285
- <title >用例管理和nosetests </title >
292
+ <title >用例管理和 nosetests </title >
286
293
287
294
<para >目前来讲,代码和测试用例共存于同一个目录。我们重构一下,将模组代码放在
288
- src目录,将测试用例放在 tests 目录。</para >
295
+ <filename >src</filename > 目录,将测试用例放在 <filename >tests</filename >
296
+ 目录。</para >
289
297
290
298
<para >执行测试用例:</para >
291
299
@@ -297,7 +305,8 @@ Traceback (most recent call last):
297
305
ImportError: No module named svnauthz
298
306
</screen >
299
307
300
- <para >在 test_svnauthz.py 文件头增加如下语句,设置Python模组查询路径:</para >
308
+ <para >在 <filename >test_svnauthz.py</filename > 文件头增加如下语句,
309
+ 设置 Python 模组查询路径:</para >
301
310
302
311
<programlisting >
303
312
import sys
@@ -306,12 +315,13 @@ sys.path.insert(0,'src')
306
315
307
316
<para >测试用例又可以成功执行了。</para >
308
317
309
- <para >tests目录下如果有多个测试用例文件,难道要一个一个去调用么?或者用
310
- unittest.TestSuite去组织测试用例?其实不用这么麻烦,nosetests
318
+ <para >目录 <filename >tests</filename > 下如果有多个测试用例文件,
319
+ 难道要一个一个去调用么?或者用 <classname >unittest.TestSuite</classname >
320
+ 去组织测试用例?其实不用这么麻烦,<application >nosetests</application >
311
321
可以自动发现目录下的测试用例,并执行。</para >
312
322
313
- <para >鼻子测试(nosetests)是一个主动发现测试用例的unittest扩展。
314
- 可以用easy_install 来安装:</para >
323
+ <para >鼻子测试(< application > nosetests</ application >)是一个主动发现测试用例的
324
+ unittest 扩展。可以用 < command >easy_install</ command > 来安装:</para >
315
325
316
326
<screen >
317
327
$ <emphasis >easy_install nose</emphasis >
346
356
<sect2 id =" psm.tdd.continued" >
347
357
<title >持续迭代</title >
348
358
349
- <para >持续迭代,完成User, Group, Alias, Rules, Module, Repos, SvnAuthz等模组。</para >
359
+ <para >持续迭代,完成 <classname >User</classname >, <classname >Group</classname >,
360
+ <classname >Alias</classname >, <classname >Rules</classname >,
361
+ <classname >Module</classname >, <classname >Repos</classname >,
362
+ <classname >SvnAuthz</classname > 等模组。</para >
350
363
351
364
</sect2 >
352
365
353
366
<!-- ================================================================= -->
354
367
<sect2 id =" psm.tdd.final" >
355
- <title >最终完成的svnauthz </title >
368
+ <title >最终完成的 svnauthz </title >
356
369
357
- <para >在Python交互模式下测试svnauthz模组 :</para >
370
+ <para >在 Python 交互模式下测试 < classname >svnauthz</ classname > 模组 :</para >
358
371
359
372
<screen >
360
373
>>> <emphasis >buff = '''# admin: / = administrator</emphasis >
395
408
['@group1 = r', 'user3 = rw', '$authenticated = ', '& admin = rw']
396
409
</screen >
397
410
398
- <para >现在是时候给 svnauthz 套上一个华丽一点的外衣了。</para >
411
+ <para >现在是时候给 < classname > svnauthz</ classname > 套上一个华丽一点的外衣了。</para >
399
412
400
413
</sect2 >
401
414
0 commit comments