Python的测试

来源:互联网 发布:淘宝网婴儿大pp裤 编辑:程序博客网 时间:2024/06/15 06:00

1.Python内是没有编译的,运行程序就是测试的过程。

2.单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。

一个测试用例仅回答一个关于它正在测试的代码问题,一个测试用例应该可以:

  • 完全自动运行,而不需要人工干预。
  • 自主判断被测试的方法是通过还是失败,而不需要人工解释结果。
  • 独立运行,而不依赖其他测试用例。即,每个测试用例都是一个孤岛。

3.程序设计的理念是以编写测试程序开始,然后编写可以通过测试的程序。测试程序就是软件的需求说明。

4.代码覆盖度:测试过程中实际运行的代码的百分比。

5.测试驱动开发过程

(1)指出需要的新特性,为其编写一个测试。

(2)编写特性的概要代码。

(3)为特性的概要编写虚设代码(dummy code),不用准确实现功能,只要满足测试要求,保证测试通过即可。

(4)重写代码。

6.Python中的测试模块:

unittest:通用测试框架

doctest:简单一些的模块,用于检查文档,但是对于编写单元测试也很在行

7.unittest是一个python版本的junit,junit是java中的单元测试框架。

8.unittest里有4个重要概念:test fixture,test case,test suite,test runner

  • 一个TestCase 的实例就是一个测试用例,所谓测试用例就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。单元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元。
  • 多个测试用例集合在一起,就是 TestSuite ,而且TestSuite 也可以嵌套TestSuite。
  • TestLoader 是用来将 TestCase 加载到 TestSuite 中,其中有几个 loadTestsFrom_() 方法,就是从各个地方寻找 TestCase ,创建它们的实例,然后添加到 TestSuite 中,再返回一个 TestSuite 实例。
  • TextTestRunner 是用来执行测试用例的,其中的 run( test ) 会执行TestSuite/TestCase 中的 run( result )方法,运行的结果保存在 TextTestResult 中。

整个测试流程就很清楚了,首先是要写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,整个过程集成在unittest.main模块中。

unittest.main() 函数负责运行测试,它会实例化所有TestCase的子类,运行所有名字以test开头的方法。

9.对一个测试用例环境的搭建和销毁,是一个fixture,通过覆盖 TestCase 的 setUp() 和 tearDown() 方法来实现。这个有什么用呢?比如说在这个测试用例中需要访问数据库,那么可以在setUp()中建立数据库连接以及进行一些初始化,在tearDown()中清除在数据库中产生的数据,然后关闭连接。注意tearDown的过程很重要,要为以后的TestCase留下一个干净的环境。关于fixture,还有一个专门的库函数叫做fixtures,功能更加强大。

至此,概念和流程基本清楚了,下面通过简单的例子再来实践一下,就拿unittest文档上的例子吧:

 

import randomimport unittestclass TestSequenceFunctions(unittest.TestCase):    def setUp(self):        self.seq = range(10)    def test_shuffle(self):        # make sure the shuffled sequence does not lose any elements        random.shuffle(self.seq)        self.seq.sort()        self.assertEqual(self.seq, range(10))        # should raise an exception for an immutable sequence        self.assertRaises(TypeError, random.shuffle, (1,2,3))    def test_choice(self):        element = random.choice(self.seq)        self.assertTrue(element in self.seq)    def test_sample(self):        with self.assertRaises(ValueError):            random.sample(self.seq, 20)        for element in random.sample(self.seq, 5):            self.assertTrue(element in self.seq)if __name__ == '__main__':    unittest.main()


TestSequenceFunctions继承自unittest.TestCase,重写了setUp()方法,并且定义了三个以'test'开头的方法,那这个TestSequenceFunctions类到底是个什么呢?它是一个测试用例,还是三个测试用例?说是三个测试用例的话,它本身继承自TestCase,说是一个测试用例的话,里面又有三个test_*()方法,明显是三个测试用例。其实,我们只要看一些TestLoader是如何加载测试用例的,就一清二楚了,在loader.TestLoader类中有一个loadTestsFromTestCase()方法:

    def loadTestsFromTestCase(self, testCaseClass):        """Return a suite of all tests cases contained in testCaseClass"""        if issubclass(testCaseClass, suite.TestSuite):            raise TypeError("Test cases should not be derived from TestSuite." \                                " Maybe you meant to derive from TestCase?")        testCaseNames = self.getTestCaseNames(testCaseClass)        if not testCaseNames and hasattr(testCaseClass, 'runTest'):            testCaseNames = ['runTest']        loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))        return loaded_suite


getTestCaseNames()是从TestCase这个类中找所有以“test”开头的方法,然后注意第9行,在构造TestSuite对象时,其参数使用了一个map方法,即对testCaseNames中的每一个元素,使用testCaseClass为其构造对象,其结果是一个TestCase的对象集合,可以用下面的代码来分步说明:getTestCaseNames()是从TestCase这个类中找所有以“test”开头的方法,然后注意第9行,在构造TestSuite对象时,其参数使用了一个map方法,即对testCaseNames中的每一个元素,使用testCaseClass为其构造对象,其结果是一个TestCase的对象集合,可以用下面的代码来分步说明:

testcases = []for name in testCaeNames:    testcases.append(TestCase(name))loaded_suite = self.suiteClass(tuple(testcases))

 

可见,对每一个以test开头的方法,都为其构建了一个TestCase对象,值得注意的是,如果没有定义test开头的方法,而是将测试代码写到了一个名为runTest的方法中,那么会为该runTest方法构建TestCase对象,如果定义了test开头的方法,就会忽略runTest方法。

至此,基本就清楚了,每一个以test开头的方法,都会为其构建TestCase 对象,也就是说TestSequenceFunctions 类中其实定义了三个TestCase,之所以写成这样,是为了方便,因为这几个测试用例的 fixture 是相同的,如果每一个测试用例单独写成一个 TestCase 的话,会有很多的冗余代码。

 

 

 

0 0
原创粉丝点击