自我实现python单元测试框架

Life is short , play more!
本文来自lihao's Blog,转载请注明。

本想写一个自动化测试框架,但由于自动化测试框架需要实现更多的自动化脚本(或是以可执行脚本,或者是以测试用例表现的一种组织形式)的解析,及结果分析工作.工作量较大, 就先写了一个轻量级的单元测试框架.
针对于自动化测试框架, 个人认为主要就是一个测试执行,测试结果回收的一个中间件. 测试脚本的解析与执行,结果回收是最主要的,也是较复杂的.

wikipedia上有关于自动化框架的专业的阐述. 我没有仔细研究过,就针对自己的想法谈一点.
1. 测试脚本的解析与执行. 测试脚本可以是一个testsiut, 多个或者1个测试用例. 如果我们实现了可以对一个测试用例进行解析执行,那么其他的就不成问题. 关键点在于, 对于用例测试的流程控制.

一个用例 从什么地方开始, 中间出现异常后的捕捉, 以及执行的策略.出现问题后是继续执行还是退出本用例. 退出本用例,则异味着下一个用例的开始.
在一个测试脚本中的一个最小”可控制”单元, 是一个”函数”. 需要是可见的函数. 如果我们在一个叫本中写3个print语句, 那么我们无法区分这3个print语句是一个测试用例,还是3个print用例. 所以通过测试框架,在执行该脚本时, 会认为是一个用例. 从第一个print,一直执行到最后一个print. 即时第一个print报错了, 那也是认为这个脚本(用例)出现了错误. 无法继续执行. 所以这样看来, 单元测试框架也是一个自动化测试框架的基础核心. 语言组织有点差了. 那么先把单元测试的例子拿出来给大家看. 对junit源代码看得比较少. 基本的测试过程有点了解.

下面是一个单元测试用例, 和单元测试框架. 当前该逻辑还有些不妥, 测试脚本中还需要写进入测试的入口. 这个应该放到测试框架中来.

import testRunner
class case:
	def tests(self):
		print 'tests'
		return 'ok'
	def abc(self):
		print 'abc'
		return 'ok'
	def gessdabc(self):
		print 'gessdabc'
		return 'ok'
	def testSetup(self):
		print 'setuping'
	def haha(self):
		print 'haha'
	def test222(self):
		print 'test222'

testRunner().run(case())

测试结果:Starting to run the testcase
setuping
=================case: test222=====================
test222
passed
=================================================
=================case: tests=====================
tests
passed
=================================================
Case passed: 2
Case failed: 0
Case Result: {‘tests’: ‘pass’, ‘test222’: ‘pass’}

单元测试框架, 会探测实例的所有方法,并将test开头的方法进行执行. testSetup 为测试用例之前初始运行. tearDown为每一个方法测试完成后执行的清除测试垃圾遗留数据方法.

import sys
import os
import inspect
import traceback

class testRunner:

	def __init__(self):
		self.casePassed=0
		self.caseFailed=0
		self.result={}

	def run(self,objectName):

		print 'Starting to run the testcase'
		self.__testSetup(objectName)
		for key in dir(objectName):
			if( key == 'testSetup' or key == 'tearDown'):
				continue
			if(self.__isTestCase(key)):
				if(self.__ismethod(objectName,key)):
					self.__executeCase(objectName,key)
					self.__testTearDown(key)
				else:
					print '%s method is not executed.it\'s prefix isnot "test"' % key
		print 'Case passed: %s' % self.casePassed
		print 'Case failed: %s' % self.caseFailed
		print 'Case Result: %s' % self.result

	def __ismethod(self,objectName,methodName):
		try:
			inspect.ismethod(objectName.__class__.__dict__[methodName].__get__(objectName,objectName.__class__))
			return True
		except:
			return False

	def __isTestCase(self,caseName):
		if(caseName[:4] == 'test'):
			return True
		return False

	def __testSetup(self,objectName):
		try:
			objectName.__class__.__dict__['testSetup'].__get__(objectName,objectName.__class__)()
			return True
		except:
			print 'No testSetup method to call , there\'s no need to setup the test envrionments '
			return False

	def __testTearDown(self,objectName):
		try:
			objectName.__class__.__dict__['tearDown'].__get__(objectName,objectName.__class__)()
			return True
		except:
			return False

	def __executeCase(self,objectName,caseName):
		print     '=================case: %s=====================' % caseName
		endInfo = '================================================='
		try:
			objectName.__class__.__dict__[caseName].__get__(objectName,objectName.__class__)()
			self.casePassed+=1
			self.result[caseName]='pass'
			print 'passed'
			print endInfo
			return True
		except:
			sys.exc_info()

			#traceback.print_exc()
			self.caseFailed+=1
			self.result[caseName]=traceback.format_exc()
			print 'failed'
			print endInfo
			return False

发表评论

电子邮件地址不会被公开。 必填项已用*标注