• Python札记 测试优先


        竹风看的第一本有关Python的书是《Dive Into Python》(简称DIP),本人觉得这本书写得是相当不错的(当然竹风无意卷入关于这本书是好是坏的争论,只要找到适合自己的资料和学习方式就好)。读《DIP》的时候,竹风对HTML和XML是一窍不通(当然现在也只是会点基本的),所以这两章是看得云里雾里的。当然也有给竹风带来震撼的章节,比如“单元测试”和“测试优先编程”。

        《DIP》中给出了一个罗马数字的程序例子,里面用到了Python中的unittest模块,这段时间竹风看了下Python 2.7的文档,结合自己的工作体会,做一个简单总结,跟大家分享一下。当然,如果错误,是竹风学艺不精,欢迎大家的指正和讨论^_^。

        参考资料:《Dive Into Python》  Mark Pilgrim  第13章.单元测试    第14章.测试优先编程 (强力推荐读一下,里面测试驱动开发的思想很值得了解)
                      《ActivePython Documentation》  这个是在windows上安装 ActiveState ActivePython 2.7 附带的

        一、简单的例子

        竹风琢磨着,程序员最好的交流就是用代码了,“翠花,上代码~~”

     1 #!/usr/bin/env python
     2  #coding: utf-8
     3  
     4  import random
     5  import unittest    #首先将 unittest 模块导入
     6  
     7  class TestSequenceFunctions(unittest.TestCase):    #继承了TestCase
     8  
     9      def setUp(self):    #初始化函数,生成10个元素的列表
    10          self.seq = range(10)
    11  
    12      def test_shuffle(self):
    13          #测试shuffled操作是否会丢失元素
    14          random.shuffle(self.seq)
    15          self.seq.sort()
    16          self.assertEqual(self.seq, range(10))    #用到了一个判断相等的断言
    17  
    18          #如果传入一个不可变的对象,比如元组,应抛出一个异常
    19          self.assertRaises(TypeError, random.shuffle, (1,2,3))
    20  
    21      def test_choice(self):
    22          #测试choice操作返回的值是否属于seq
    23          element = random.choice(self.seq)
    24          self.assertTrue(element in self.seq)    #用到了一个判断值为真的断言
    25  
    26      def test_sample(self):
    27          #测试sample操作返回的结果是否属于seq
    28          self.assertRaises(    #当传入的参数有误时,应抛出一个异常
    29              ValueError, random.sample, self.seq, 20
    30          )
    31          for element in random.sample(self.seq, 5):
    32              self.assertTrue(element in self.seq)    #用到了一个判断值为真的断言
    33  
    34  if __name__ == '__main__':
    35      unittest.main()

        竹风在文档的例子上稍微加了点注释,这个例子对各位园友来说应该是小菜一碟了。如果使用的是Python 2.7的话,还可以将28-30行修改为:

    1         with self.assertRaises(ValueError):
    2             random.sample(self.seq, 20)

        运行起来应该是这个样子的:   

    1 $ python TestSequenceFuncions.py
    2 ...
    3 ----------------------------------------------------------------------
    4 Ran 3 tests in 0.000s
    5 
    6 OK

        如果想看稍微详细点的测试信息,可以将最后一行 “unittest.main()” 修改如下:

        suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
        unittest.TextTestRunner(verbosity=2).run(suite)

        这时候输出信息就会稍微详细一点:

    $ python TestSequenceFuncions.py
    test_choice (__main__.TestSequenceFunctions) ... ok
    test_sample (__main__.TestSequenceFunctions) ... ok
    test_shuffle (__main__.TestSequenceFunctions) ... ok
    
    ----------------------------------------------------------------------
    Ran 3 tests in 0.000s
    
    OK

        如果还觉得不够详细,那么可以在命令行上加 -v 选项:

    $ python -v TestSequenceFuncions.py

    不过这个输出到屏幕的信息已经达到刷屏的程度了。。。大家还是慎用。。。


        二、测试的顺序与命名规范

        不知道各位园友注意到了没有,测试的顺序是跟class里面定义的def的顺序无关的。
    在class的定义顺序是:(test_shuffle,test_choice,test_sample);
    而实际测试的时候是:(test_choice,test_sample,test_shuffle);
    根据竹风的个人经验,测试的顺序应该是在去掉 “test_” 前缀后,按照字母顺序排序。
        还需要提到的一点是,需要测试的 def 需要以 “test_” 为前缀。针对这点,我们可以写一个 “make_test_data” 的函数准备测试数据,再写一个 “clean_test_data” 的函数清理测试数据。
        PS:根据《DIP》里面提到关于测试的两个基本原则:
        一、每个测试用例只回答一个问题。
        二、每个测试用例必须可以与其他测试用例隔离工作,每个测试用例是一个“孤岛”。
    根据这两个基本原则,的确应该与定义他们的顺序无关的

        三、初始化(setUp)和清理工作(tearDown

        如果竹风用“make_test_data”来创建测试数据,竹风的基友用的是"create_test_data",一千个程序员可能就带来一千种命名方式,这五花八门的函数名字可就真的让人头疼了。
        根据Python里“import this”的精神,应该会有专门的函数来执行初始化或者清理工作的。也的确有这两个函数,setUp 与 tearDown 分别负责 初始化 清理 工作。
        setUp函数总是第一个调用,而tearDown函数则总是在最后一个调用。现在函数调用的顺序也大概理清楚了:setUp --> test_* --> tearDown。

        四、常用的断言方法(assert methods)

        最后水一下几个常用的断言。
        assertEqual(first, second, msg=None)
        assertNotEqual(first, second, msg=None)
        判断first和second是否相等(不等),msg为测试失败时给出的信息。msg一般使用默认值就行


        assertTrue(expr, msg=None)
        assertFalse(expr, msg=None)
        判断expr的值是否为真(假),msg为测试失败时给出的信息。


        assertRaises(exception, callable, *args, **kwds)    #参数魔法里面有提到过的哦
        assertRaises(exception)
        判断是否抛出一个异常,*args和 **kwds 为调用 callable 需要传的参数,注意这里callable的传参数方式。可参照上面的例子。

        到这里竹风这个简单的分享也结束了,用上面的这些内容,写个简单的测试用例问题应该不大了。
        测试个人感觉上是一个很大的领域,竹风也只是刚接触。
        建议有兴趣的园友看一下《DIP》的13、14章,当然也可以看下Python的文档。
        祝大家新年快乐,万事如意^_^

  • 相关阅读:
    PHP实现对站点内容外部链接的过滤方法
    PHP常用技术文之文件操作和目录操作总结
    PHP实现手机号码中间四位用星号(*)隐藏的自定义函数分享
    PHP如何快速读取大文件
    php使用json_encode后出现中文乱码的解决方法
    redis在PHP中的基本使用
    等差数列的概念和性质
    构造数列中的常见变形总结
    用几何画板制作函数图像的动态伸缩效果
    用几何画板制作函数图像的动态平移效果
  • 原文地址:https://www.cnblogs.com/PandaBamboo/p/2907387.html
Copyright © 2020-2023  润新知