近年来测试驱动开发(TDD)受到越来越多的关注。这是一个持续改进的过程,能从一开始就形成规范,帮助提高代码质量。这是切实可行的而非天马行空的。
TDD的全过程是非常简单的。借助TDD,代码质量会得到提升,同时可以让你保持清晰的思路。TDD与敏捷开发可谓强强联合,特别是在进行结对编程的时候。本文主要介绍了TDD的核心概念,还有结合nosetest单元测试包进行Python示例简析。另外还会介绍一些Python备用包。
TDD是什么?
使用该方法可让你少走前人的弯路
顾名思义,TDD即进行编程时先把测试部分写好,当发现不能通过时,再进行编程以使测试通过。然后在这基础上适当地调整测试代码以实现更多功能,最后再编写代码使之实现。
TDD看起来非常像一个环,首先是要不断调整测试代码,然后是编码,改进,最后直至完成。先实现测试部分的做法会使你自然养成把问题放在首位的思维习惯。当真正去构建代码时,就不得不想清楚该如何把设计做好;比方说,该方法有何返回值?当遇到异常时该怎么办?诸如此类。
以这样的方式进行开发,意味着要想出不同的代码实现路径,并在测试中进行实践。这样做可使你少走前人的弯路:陷入一个问题后写出毫不相关的解决方案。
该过程可描述如下:
与敏捷开发结合
TDD与敏捷开发并行不悖甚至1+1远大于2,这里指的是代码质量而不是数量。
“这意味着结对双方都会参与其中,着重于当前工作,然后在每个环节进行互检。”
然而在结对编程时TDD是单独进行的。如果能把双方的开发流程混合好,互相都能理解就最好不过了。例如,其中一人写出单元测试,当测试通过后,另外一人可以编写不同的测试以之通过。
任何时候结对双方都可以互换角色,每半天或天。这意味着结对双方都会参与其中,每人都把精力放在当前任务上,然后在每个环节进行交叉互检。这难道不是一个双赢的做法吗?
TDD也可以是行为驱动开发过程中的组成部分,同样地,首先写出测试,只不过这里指的是接受测试。这样有助于把工作从头到尾都保持规范。
单元测试语法
进行单元测试时,使用到的Python方法如下:
以上是实际当中使用频率最高的方法,更多的方法请查阅Python单元测试文档。
安装并使用Python Nose
进行下面的练习前,请把nosetest测试运行包安装好。使用标准pip语句进行安装是最直接的做法。此外在项目中使用VirtualEnv(Python虚拟环境)也是不错的做法,因为它可确保所有包在不同项目中是独立的。假如对pip或VirtualEnv了解不多,不妨先查阅相关文档:VirtualEnv,PIP。
pip语句十分简洁:
1 | \”pip install nose\” |
安装完成后,可以执行单个测试文件
1 | $ nosetests example_unit_test.py |
或者可以直接执行文件夹中的文件组
1 | $ nosetests /path/to/tests |
这里要注意的是每个测试方法都应以“test_”为开头,这样nosetest运行机才能正确识别出目标测试文件。
可选参数
下面介绍几个有用的命令行参数:
实例分析和测试驱动方法
接下来结合一个简单的计算器类例子例如相加/相减,来讲述Python单元测试和TDD概念。对于add相加功能,会尝试编写一个缺陷测试。
在一个空白项目中,首先创建两个python包app和test。然后在每个文件里建立两个名为_init_.py空白文件。这是Phthon工程的标准结构,完成后可以拥有一个可导入的文件结构。如果需要了解更多有关文档架构的信息,请查阅Python包说明文档。 在测试目录里创建一个test_calulator.py文件,其代码如下:
123456 | import unittestclass TddInPythonExample(unittest.TestCase): def test_calculator_add_method_returns_correct_result(self): calc = Calculator() result = calc.add(2,2) self.assertEqual(4, result) |
说明:
完成后可着手编写测试代码了。执行方法前要先对计算器进行初始化,初始化完成后便可调用add方法,并把结果存入变量result中。完成后,使用unittest的assertEqual方法来确保add方法正常执行。
现在可以启动nosetest来执行测试文件了。代码如下:
12 | if __name__ == \’__main__\’: unittest.main() |
标准的Python文件执行方式为$ python test_calculator.py,相比之下本文使用的nosetests方法功能更丰富,例如可以运行目录中的全部测试文件。
1234567891011121314 | $ nosetests test_calculator.pyE======================================================================ERROR: test_calculator_add_method_returns_correct_result (test.test_calculator.TddInPythonExample)———————————————————————————————————Traceback (most recent call last): File \”/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py\”, line 6, in test_calculator_add_method_returns_correct_result calc = Calculator()NameError: global name \’Calculator\’ is not defined ———————————————————————————————————Ran 1 test in 0.001s FAILED (errors=1) |
运行后可见出错的原因是没有导入Caculator。因为还没有创建呢!创建的方法是在app目录下建立calculator.py文件,然后导入:
ȋ是非常简单的。借助TDD,代码质量会得到提升,同时可以让你保持清晰的思路。TDD与敏捷开发可谓强强联合,特别是在进行结对编程的时候。本文主要介绍了TDD的核心概念,还有结合nosetest单元测试包进行Python示例简析。另外还会介绍一些Python备用包。
TDD是什么?
使用该方法可让你少走前人的弯路
顾名思义,TDD即进行编程时先把测试部分写好,当发现不能通过时,再进行编程以使测试通过。然后在这基础上适当地调整测试代码以实现更多功能,最后再编写代码使之实现。
TDD看起来非常像一个环,首先是要不断调整测试代码,然后是编码,改进,最后直至完成。先实现测试部分的做法会使你自然养成把问题放在首位的思维习惯。当真正去构建代码时,就不得不想清楚该如何把设计做好;比方说,该方法有何返回值?当遇到异常时该怎么办?诸如此类。
以这样的方式进行开发,意味着要想出不同的代码实现路径,并在测试中进行实践。这样做可使你少走前人的弯路:陷入一个问题后写出毫不相关的解决方案。
该过程可描述如下:
与敏捷开发结合
TDD与敏捷开发并行不悖甚至1+1远大于2,这里指的是代码质量而不是数量。
“这意味着结对双方都会参与其中,着重于当前工作,然后在每个环节进行互检。”
然而在结对编程时TDD是单独进行的。如果能把双方的开发流程混合好,互相都能理解就最好不过了。例如,其中一人写出单元测试,当测试通过后,另外一人可以编写不同的测试以之通过。
任何时候结对双方都可以互换角色,每半天或天。这意味着结对双方都会参与其中,每人都把精力放在当前任务上,然后在每个环节进行交叉互检。这难道不是一个双赢的做法吗?
TDD也可以是行为驱动开发过程中的组成部分,同样地,首先写出测试,只不过这里指的是接受测试。这样有助于把工作从头到尾都保持规范。
单元测试语法
进行单元测试时,使用到的Python方法如下:
以上是实际当中使用频率最高的方法,更多的方法请查阅Python单元测试文档。
安装并使用Python Nose
进行下面的练习前,请把nosetest测试运行包安装好。使用标准pip语句进行安装是最直接的做法。此外在项目中使用VirtualEnv(Python虚拟环境)也是不错的做法,因为它可确保所有包在不同项目中是独立的。假如对pip或VirtualEnv了解不多,不妨先查阅相关文档:VirtualEnv,PIP。
pip语句十分简洁:
1 | \”pip install nose\” |
安装完成后,可以执行单个测试文件
1 | $ nosetests example_unit_test.py |
或者可以直接执行文件夹中的文件组
1 | $ nosetests /path/to/tests |
这里要注意的是每个测试方法都应以“test_”为开头,这样nosetest运行机才能正确识别出目标测试文件。
可选参数
下面介绍几个有用的命令行参数:
实例分析和测试驱动方法
接下来结合一个简单的计算器类例子例如相加/相减,来讲述Python单元测试和TDD概念。对于add相加功能,会尝试编写一个缺陷测试。
在一个空白项目中,首先创建两个python包app和test。然后在每个文件里建立两个名为_init_.py空白文件。这是Phthon工程的标准结构,完成后可以拥有一个可导入的文件结构。如果需要了解更多有关文档架构的信息,请查阅Python包说明文档。 在测试目录里创建一个test_calulator.py文件,其代码如下:
123456 | import unittestclass TddInPythonExample(unittest.TestCase): def test_calculator_add_method_returns_correct_result(self): calc = Calculator() result = calc.add(2,2) self.assertEqual(4, result) |
说明:
完成后可着手编写测试代码了。执行方法前要先对计算器进行初始化,初始化完成后便可调用add方法,并把结果存入变量result中。完成后,使用unittest的assertEqual方法来确保add方法正常执行。
现在可以启动nosetest来执行测试文件了。代码如下:
12 | if __name__ == \’__main__\’: unittest.main() |
标准的Python文件执行方式为$ python test_calculator.py,相比之下本文使用的nosetests方法功能更丰富,例如可以运行目录中的全部测试文件。
1234567891011121314 | $ nosetests test_calculator.pyE======================================================================ERROR: test_calculator_add_method_returns_correct_result (test.test_calculator.TddInPythonExample)———————————————————————————————————Traceback (most recent call last): File \”/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py\”, line 6, in test_calculator_add_method_returns_correct_result calc = Calculator()NameError: global name \’Calculator\’ is not defined ——————————————————————————————————— |