UNSW COMP9021 2019T2

COMP9021 Principles of Programmi

2017-08-07  本文已影响0人  Sisyphus235

Python TDD(Testing Driven Development)详解

coding的形成过程应该是从special case入手,找到general solving methods,为了提高编码效率,TDD是一个不错的办法。

实例:
输入——一个自然数list
功能——按照list的顺序先输出list中所有偶数,再输出剩下的奇数
输出——功能化后的list

1.实例实现

应用之前提到的python list生成的优化写法:

def f(L):
    return [e for e in L if e % 2 == 0] + [e for e in L if e % 2 == 1]

这种写法效率不高,因为要2次遍历数组L分别找偶数和奇数,可以优化为:

def f(L):
    even_member = []
    odd_member = []
    for e in L:
        if e % 2 == 0:
            even_member.append(e)
        else:
            odd_member.append(e)
    return even_member + odd_member

2.Test设计

这个实例是关于奇偶数的排序,所以应该包含如下的测试
(1)[]
(2)[奇数]
(3)[偶数]
(4)[奇数, 奇数]
(5)[偶数,偶数]
(6)[奇数,偶数]
(7)[偶数,奇数]
(8)[偶数,偶数,偶数,偶数]
(9)[奇数, 奇数,奇数, 奇数]
(10)[奇数,偶数,偶数...]

3.原程序中人肉输出检验

使用print()函数显示出来,人肉核对是否正确。

print(f([]))
print(f([0]))
print(f([1]))
print(f([0, 2]))
print(f([1, 3]))
print(f([0, 3]))
print(f([3, 0]))
print(f([2, 0, 8, 6]))
print(f([5, 1, 3, 9]))
print(f([2, 7, 8, 3, 4]))

4.原程序中设置检验函数

人肉检验的问题不仅是伤身,更是会影响函数调用。如果其他程序调用了一个包含这么多人肉输出代码的程序,跑出来的结果会非常尴尬。设想如果你打开微信,结果微信由于调用了这样一个程序,导致你的界面上有若干测试结果,只能用灾难形容。
一个小进步是先解决程序调用问题。

def f(L):
    return [e for e in L if e % 2 == 0] + [e for e in L if e % 2 == 1]
print("Name of module: ", __name__)

if __name__ == '__main__':
    print('\nTesting [], result should be [].')
    print(f([]) == [])
    print('\nTesting [0], result should be [0].')
    print(f([0]) == [0])
    print('\nTesting [1], result should be [1].')
    print(f([1]) == [1])
    print('\nTesting [0, 1], result should be [0, 1].')
    print(f([0, 1]) == [0, 1])
    print('\nTesting [1, 0], result should be [0, 1].')
    print(f([1, 0]) == [0, 1])
    print('\nTesting [3, 0, 11, 17, 10, 11, 17, 15, 18, 5], result should be [0, 10, 18, 3, 11, 17, 11, 17, 15, 5].')
    print(f([3, 0, 11, 17, 10, 11, 17, 15, 18, 5]) == [0, 10, 18, 3, 11, 17, 11, 17, 15, 5])

由于在人肉输出的时候有了限制条件if __name__ == '__main__',含义是这个程序名称是不是main,所以解决了刚才人肉输出的调用问题。
在函数调用时,当前的程序名称是main,被调用的程序名称是其“文件名”。这样在调用上述函数的时候,if条件不满足,各种检验不会运行。
另外,对人肉工作做了一点优化,不再需要人肉核对所有list元素,而是直接给出True or False的结果。

5.写测试程序

实际工作中,不同module是严格分开的,测试程序一般要在新的python文件下编码,需要测试的时候可以方便调用。

def f(L):
    return [e for e in L if e % 2 == 0] + [e for e in L if e % 2 == 1]

if __name__ == '__main__':
    import test
    test.test()

上述程序在源程序相同路径下存放有一个文件名为"test"的测试程序,import后运行其中的test()函数。这里注意,不要忘记写if条件,否则调用的时候可能会由于路径问题报错。

6.Python prompt测试

分开写测试文件确实常见,但是对于小的函数未免太过麻烦,所以最推荐的做法是利用python prompt做测试。

def f(L):
    '''
    >>> f([])
    []
    >>> f([0, 1])
    [0, 1]
    >>> f([1, 0])
    [1, 0]
    '''
    return [e for e in L if e % 2 == 0] + [e for e in L if e % 2 == 1]
import doctest
doctest.testmod()

写法是在def函数下一行缩减后,写入多行注释。在注释中,>>>代表python的prompt,后面写的是设计好的测试,换行后给出预期的结果。如果结果不同,python运行时会报错。

上一篇下一篇

猜你喜欢

热点阅读