TDD in Expert Python Programmin
Test-Driven Development Principles
TDD consists of writing test cases that cover a desired feature, then writing the feature itself. In other words, the usage examples are written before the code even exists.
For example, a developer who is asked to write a function that provides the average value of a sequence of numbers will first write a few examples on how to use it, and
the expected results:
assert average(1, 2, 3) == 2
assert average(1, -3) == -1
These examples can be provided by another person as well. From there, the function can be implemented until the two examples work:
>>> def average(*numbers):
... return sum(numbers) / len(numbers)
...
>>> assert average(1, 2, 3) == 2
>>> assert average(1, -3) == -1
A bug or an unexpected result is a new example of usage the function should be able to deal with:
>>> assert average(0, 1) == 0.5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
The code can be changed accordingly, until the new test passes:
>>> def average(*numbers):
... # makes sure all numbers can be used as floats
... numbers = [float(number) for number in numbers]
... return sum(numbers) / float(len(numbers))
...
>>> assert average(0, 1) == 0.5
And more cases will make the code evolve:
>>> try:
... average()
... except TypeError:
... # we want an empty sequence to throw a type error
... pass
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 3, in average
ZeroDivisionError: integer division or modulo by zero
>>>
>>> def average(*numbers):
... if numbers == ():
... raise TypeError(('You need to provide at '
... 'least one number'))
... numbers = [float(number) for number in numbers]
... return sum(numbers) / len(numbers)
...
>>> try:
... average()
... except TypeError:
... pass
...
From there all tests can be gathered in a test function, which is run
every time the code evolves:
>>> def test_average():
... assert average(1, 2, 3) == 2
... assert average(1, -3) == -1
... assert average(0, 1) == 0.5
... try:
... average()
... except TypeError:
... pass
...
>>> test_average()
Every time a change is made, test_average is changed together with average,then run again to make sure all cases still work. The usage is to gather all tests in the tests folder of the current package. Each module can have a corresponding test module there.This approach provides a lot of benefits by:
• Preventing software regression
• Improving code quality
• Providing the best low-level documentation
• Producing robust code faster
Preventing Software Regression
We all face software regression issues in our developer lives. Software regression is a new bug introduced by a change. Regressions happen because of the simple fact that it is impossible at some point to guess what a single change in a codebase might lead to. Changing some code might break some other features, and sometimes lead to vicious side effects, such as silently corrupting data.
To avoid regression, the whole set of features software provides should be tested every time a change occurs.
Opening a codebase to several developers amplifies the problem, since each person will not be fully aware of all development activities. While having a version control system prevents conflicts, it does not prevent all unwanted interactions.
TDD helps reduce software regression. The whole software can be automatically tested after each change. This will work as long as each feature has the proper set of
tests. When TDD is properly done, the test base grows together with the codebase. Since a full test campaign can last for quite a long time, it is a good practice to delegate it to a buildbot, which can do the work in the background (this is described in Chapter 8). But local re-launching of the tests should be done manually by the user, at least for the concerned modules.
Improving Code Quality
When a new module, class, or a function is written, a developer focuses on how to write it and how to produce the best piece of code he or she can. But while he or she
is concentrating on algorithms, he or she might lose the user's point of view: How and when will his or her function be used? Are the arguments easy and logical to use? Is the name of the API right?
This is done by applying the tips described in the previous chapters, such as Choosing Good Names. But the only way to do it efficiently is to write usage examples. This is when the developer realizes if the code he or she wrote is logical and easy to use. Often, the first refactoring occurs right after the module, class, or function is finished.
Writing tests, which are use cases for the code, helps in having this user point of view. Developers will, therefore, often produce a better code when they use TDD. It is difficult to test gigantic functions that both calculate things as well as have side effects. Code that is written with testing in mind tends to be architected more cleanly
and modularly.
Providing the Best Developer Documentation
Tests are the best place for a developer to learn how software works. They are the use cases the code was primarily created for. Reading them provides a quick and deep
insight into how the code works. Sometimes, an example is worth a thousand words. The fact that these tests are always up to date with the codebase makes them the best
developer documentation a piece of software can have. Tests don't go stale in the same way documentation does, otherwise they would fail.
Producing Robust Code Faster
Writing without tests leads to extensive debugging sessions. A bug in one part of the software might be felt in a distant part of that software. Since you don't know who to
blame, you spend an inordinate amount of time debugging. It's better to fight small bugs one at a time when a test fails, because you'll have a better clue as to where the
real problem is. And testing is often more fun that debugging because it is coding.
If you measure the time taken to fix the code together with the time taken to write it, it will usually be longer than the time a TDD approach would take. This is not obvious when you start a new piece of code. This is because the time taken to set up test environment and write the first few tests is extremely long compared to the time taken just to write the first pieces of code.
But there are some test environments that are really hard to set up. For instance, when your code interacts with an LDAP or an SQL server, writing tests is not obvious at all. This is covered in the Fakes and Mocks section in this chapter.
TDD in Expert Python Programmin的更多相关文章
- Expert Python programming - Reading Notes
1. MRO: method resolution order lookup order: L(MyClass) = [MyClass, merged(L(Base1), L(Base2), Base ...
- python BDD&TDD
教程一:行为驱动开发(BDD) 基于Python的行为驱动开发实战: http://python.jobbole.com/81303/ 基于Python的行为驱动开发实战 英语原文地址: http:/ ...
- [Python] 学习资料汇总
Python是一种面向对象的解释性的计算机程序设计语言,也是一种功能强大且完善的通用型语言,已经有十多年的发展历史,成熟且稳定.Python 具有脚本语言中最丰富和强大的类库,足以支持绝大多数日常应用 ...
- Python学习资料下载地址(转)
[转]Python学习资料和教程pdf 开发工具: Python语言集成开发环境 Wingware WingIDE Professional v3.2.12 Python语言集成开发环境 Wingwa ...
- [转]Python学习资料和教程pdf
开发工具: Python语言集成开发环境 Wingware WingIDE Professional v3.2.12 Python语言集成开发环境 Wingware WingIDE Professio ...
- 原创翻译-测试驱动开发(TDD)
测试驱动开发原则 翻译自<<Expert Python Programming>> 测试驱动开发是指首先编写包含所有测试软件特点的测试集,然后再去开发软件.也就是说,在编写软件 ...
- 关于Python编程的一些问答
关于Python编程的一些问答 导语 大约1个月前,oschina.net和华章图书一起合作做了一个活动:OSC第51期高手问答--聊聊python那些事,来推广我参与撰写的书<编写高质量代码: ...
- 转:Python语言编程学习资料(电子书+视频教程)下载汇总
开发工具: Python语言集成开发环境 Wingware WingIDE Professional v3.2.12 Python语言集成开发环境 Wingware WingIDE Professio ...
- 关于Python Package下的Module import方式[转]
2012年有一个目标我没有达成,那就是深入学习和使用Python语言.这个目标被其他学习任务和工作无情的抢占了,当然最主要的原因还是我重视不够^_^. 近期恰逢有一些Python工程的开发工作要做,就 ...
随机推荐
- .net经验积累
希望对.net编程者有所帮助 1.学会配置环境变量 1.我的电脑-属性-环境变量-双击下面的path-粘贴路径 2.ctrl+r 输入软件名字按回车 2.常用vs2010快捷键 代码格式化:ct ...
- [Architecture Design] 3-Layer基础架构
[Architecture Design] 3-Layer基础架构 三层式体系结构 只要是软件从业人员,不管是不是本科系出身的,相信对于三层式体系结构一定都不陌生.在三层式体系结构中,将软件开发所产出 ...
- 通过GPS数据反向地理信息编码, 得到当前位置信息
检查可用性 这属于基础知识, 不赘述, 总的来说,你的设备的支持要打开, 添加CoreLocation的framework, 引用头文件, 添加委托,然后, 好的实践是在使用前编程检查相关可用性: - ...
- js中的浅拷贝和深拷贝
说说最近所学:浅拷贝和深拷贝也叫做浅克隆和深克隆,深浅主要针对的是对象的"深度",常见的对象都是"浅"的,也就是对象里的属性就是单个的属性,而"深&q ...
- CSS3随内容自动伸缩的背景
CSS3给我们带来一个非常实用的新属性:border-image,利用这个属性我们可以做出随着内容的增减自动伸缩的背景.废话不多说,看代码! HTML: <ol> <li>第一 ...
- android 开源和一些博客总结
记录一些开源的android库 (1)Http请求库封装 https://github.com/kevinsawicki/http-request (2)浮动组件,定制化 toast http://f ...
- ListView的addHeaderView()方法相关问题
使用listView.addHeaderView(view) 可以在 listView 上方添加一个view视图 ,使listView和这个view连接在一起 效果上看上去是一个整体 一般用于上拉刷新 ...
- 浅析LruCache原理
Android用LruCache来取代原来强引用和软引用实现内存缓存,因为据说自2.3以后Android将更频繁的调用GC,导致软引用缓存的数据极易被释放. LruCache使用一个LinkedHas ...
- 我对XCode Objective-c Cocoa的简单理解
我对XCode Objective-c Cocoa的简单理解 Xcode Xcode说的通俗一点就是开发OS X 和 iOS 应用程序的. 如果我们想要认真点说 ,Xcode 是运行在操作系统Mac ...
- iOS开发之网络编程--2、NSURLSessionDownloadTask文件下载
本文内容大纲: 1.回顾NSURLSessionTask 2.NSURLSessionDownloadTask大文件之block下载 3.NSURLSessionDownloadTask大文件之代理方 ...