TTD in Expert Python Programming

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.

时间: 2024-11-06 09:58:25

TTD in Expert Python Programming的相关文章

《Expert Python Programming》pdf

下载地址:网盘下载 内容简介  · · · · · · Python is a dynamic programming language, used in a wide range of domains by programmers who find it simple, yet powerful. From the earliest version 15 years ago to the current one, it has constantly evolved with productiv

Expert Python programming - Reading Notes

1. MRO: method resolution order lookup order: L(MyClass) = [MyClass, merged(L(Base1), L(Base2), Base1, Base2)] 2. super(...) 必须所有的父类都call super, 不然会有不可预测的问题 3. class variable & instance variable 查找顺序 都可以通过 self.x 访问, 所以instance variable 会覆盖class vari

C专家编程 Expert C Programming

该书中一些思想还是比较有用的,但随着编译器以及规范的变化,书中有些内容已经发生了变化,以下是实践之后的一些总结. 1 - typedef int x[10] 和 define x int[10]  区别 define 定义为变量替换,而typedef为声明替换; #define peach int; unsigned peach i;  //wrong typedef int banana; unsigned banana i; //wrong 声明替换用typedef 识别数组和函数指针 e.

Master the 10 Most Common Python Programming Problems - 10大最常见的Python编程错误

http://blog.csdn.net/pipisorry/article/details/45175457 Introduction 本文介绍python编程中很难捕捉10大错误 (Note: This article is intended for a more advanced audience than Common Mistakes of Python Programmers, which is geared(适合) more toward those who are newer t

C语言学习书籍推荐《C专家编程Expert C Programming Deep C Secrets》下载

Peter Van Der Linden (作者) <C和C++经典著作 C专家编程Expert C Programming Deep C Secrets>展示了C程序员所使用的编码技巧,并专门开辟了一章对C++的基础知识进行了介绍.书中C的历史.语言特性.声明.数组.指针.链接.运行时.内存以及如何进一步学习C++等问题进行了细致的讲解和深入的分析.全书撷取几十个实例进行讲解,对C程序员具有非常高的实用价值.<C和C++经典著作?C专家编程Expert C Programming De

第一次碰到try-except(core python programming 2nd Edition 3.6)

1 # coding: utf-8 # 使用Windows系统,首行'#!/usr/bin/env Pyton'无用,全部改为'# coding: utf-8' 2 3 'readtextfile.py -- read and display text file' 4 5 # get filename 6 fname = raw_input('Enter filename: ') 7 print 8 9 # attempt to open file for reading 10 try: 11

Python——函数,模块,简单文件读写(python programming)

函数(function)定义原则: 最大化代码重用,最小化代码冗余,流程符合思维逻辑,少用递归; 函数的定义方法: def function_name(param_1, param_2): ..... return output  #输出,结束函数 注意: 函数要在使用之前定义函数的使用方法以print()函数为例形式参数和实际参数在函数内定义的变量为本地变量,在函数外无法访问 参数传递: 实际参数通过赋值运算传递给形式参数注意:如果参数是列表,在函数内可以被修改 (列表可以原位传递) 1 de

Python——字符串(python programming)

p ython——字符串 ①加法 连接两个字符串 ②乘法  复制字符串 python——转义字符 \n 换行 \' 单引号 \'' 双引号 \\ 反斜杠 raw字符串:无视转义字符 转义: 字符串和数字相互转化 函数str(), int(), float() 字符串方法:查找 字符串的方法函数s1.find(s2)在字符串s1中查找字符串s2,若找到,返回首次找到的位置 -1 表示没找到 字符串替换 字符串:大小写转换 s.upper() s.lower s.capitalize()  一句话首

数值运算内建函数(core python programming 2nd edition 5.6.2)

数值运算内建函数 函数  功能 abs(num) 返回 num 的绝对值 coerce(num1, num2) 将num1和num2转换为同一类型,然后以一个元组的形式返回. divmod(num1, num2) 除法-取余运算的结合.返回一个元组(num1/num2,num1 %num2).对浮点数和复数的商进行下舍入(复数仅取实数部分的商). pow(num1, num2, mod=1) 取num1 的num2次方,如果提供mod参数,则计算结果再对mod进行取余运算. round(flt,