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工程的开发工作要做,就 ...
随机推荐
- (旧)子数涵数·Flash——影片剪辑的事件操作
一.综述 1.概念:影片剪辑的事件操作,就是onClipEvent命令,就如同在按钮上使用的on命令. 2.方法:onClipEnvent(参数){命令} 3.参数:onClipEnvent有许多的参 ...
- 蒙特卡洛树搜索算法(UCT): 一个程序猿进化的故事
前言: 本文是根据的文章Introduction to Monte Carlo Tree Search by Jeff Bradberry所写. Jeff Bradberry还提供了一整套的例子,用p ...
- 六个创建模式之工厂方法模式(Factory Method Pattern)
问题: 在使用简单工厂模式的时候,如果添加新的产品类,则必需修改工厂类,违反了开闭原则. 定义: 定义一个用于创建对象的接口,让子类决定具体实例化哪个产品类.此时工厂和产品都具有相同的继承结构,抽象产 ...
- 求Mac 的adt插件!
搞了半天原来ADT Mac和win是通用的安装方法也相同! 自己配环境! 下载一个Eclipse,然后安装就行! dns:203.195.223.190 这个DNS可以连上谷歌的服务器(只限学习使用) ...
- 将 C# 编译为原生机器码
C# 用户似乎都希望 C# 可以和 C++ 一样编译为本地的机器码.如果 C# 可以编译为机器码,将可以做到: 1. 效率提高,可以取代 C++ . 2. 反编译. 当然微软在商业利益的考虑下 ...
- 2015年第8本(英文第7本):the city of ember 微光城市
书名:the City of Ember(中文名:微光城市) 作者:Jeanne DuPrau 单词数:6.2万 不重复单词数:未知 首万词不重复单词数:未知 蓝思值:未知 阅读时间:2015年4月2 ...
- 获取当前屏幕显示的viewcontroller
//获取当前屏幕显示的viewcontroller - (UIViewController *)getCurrentVC { UIViewController *result = nil; UIWin ...
- 复杂对象的本地化(以Person为例)
Person.h #import <Foundation/Foundation.h> @interface Person : NSObject <NSCoding> /// 姓 ...
- IOS项目集成ShareSDK实现第三方登录、分享、关注等功能。
(1)官方下载ShareSDK iOS 2.8.8,地址:http://sharesdk.cn/ (2)根据实际情况,引入相关的库,参考官方文档. (3)在项目的AppDelegate中一般情况下有三 ...
- 朝花夕拾-android 获取当前手机的内存卡状态和网络连接状态
序言: 人的一生是一个选择的过程. 如果脚下只有一条路,只要一往无前即可,不用担心走错.即使是错也别无它法.然而人是不安分的,况且安于独木桥的行走,其目的地由于没有蜿蜒曲折去遮挡行路人的视线,一往无前 ...