写在前面
这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许优质的单元测试是一个切入点。 就我个人而言,这本书确实很有帮助。第一次读的时候,很多细节我都不太懂,但将书中内容应用到工作中后,我受益匪浅。比如面对一些让人抓狂的代码设计时,书里的方法能让我逐步深入理解代码的逻辑与设计。 作为一名测试开发工程师,我想把学习这本书的经验分享给大家,希望能给大家带来帮助。因为现在工作中大多使用 Python 代码,所以我把书中JAVA案例都用 Python 代码进行了改写 。
在前面的博客中,我们深入探讨了xUnit测试框架里测试的资源清理、日志记录以及tearDown方法的实现等内容。接下来,我们将继续探索书中关于测试计数以及处理测试失败等方面的知识,并通过完整的示例代码来呈现。
测试计数功能的实现
目标与需求
我们打算实现一个功能,确保无论测试方法出现何种异常,tearDown方法都会被调用,并且希望捕获这些异常并记录到测试结果中。同时,我们希望TestCase.run()方法返回一个TestResult对象,用于记录测试运行的结果,包括运行的测试数目和失败的测试数目等信息。
代码实现过程
- 伪实现阶段 :
我们先从伪实现开始,定义TestResult类并提供一个简单的summary方法:
python
class TestResult:
def summary(self):
return "1 run, 0 failed"
同时,更新TestCase类的run方法,使其返回TestResult对象:
python
class TestCase:
def __init__(self, name):
self.name = name
def setUp(self):
pass
def tearDown(self):
pass
def run(self):
self.setUp()
method = getattr(self, self.name)
method()
self.tearDown()
return TestResult()
- 完善TestResult类 :
为了准确记录测试数目,我们需要对TestResult类进行改进。将runCount初始化为0,每运行一个测试就将其加1:
python
class TestResult:
def __init__(self):
self.runCount = 0
def testStarted(self):
self.runCount = self.runCount + 1
def summary(self):
return "%d run, 0 failed" % self.runCount
- 更新TestCase类的run方法 :
在TestCase类的run方法中,调用testStarted方法来更新测试计数:
python
class TestCase:
def __init__(self, name):
self.name = name
def setUp(self):
pass
def tearDown(self):
pass
def run(self):
result = TestResult()
result.testStarted()
self.setUp()
method = getattr(self, self.name)
method()
self.tearDown()
return result
- 测试失败的情况 :
为了测试测试失败时的情况,我们编写一个新的测试testFailedResult,以及在WasRun类中定义一个会抛出异常的testBrokenMethod方法:
python
class TestCaseTest(TestCase):
def testFailedResult(self):
test = WasRun("testBrokenMethod")
result = test.run()
assert "1 run, 1 failed" == result.summary()
class WasRun:
def __init__(self, name):
self.name = name
self.wasRun = None
self.log = ""
def setUp(self):
self.wasRun = None
self.log = "setUp "
def testMethod(self):
self.wasRun = 1
self.log = self.log + "testMethod"
def tearDown(self):
self.log = self.log + " tearDown"
def testBrokenMethod(self):
raise Exception
目前,上述测试会存在问题,因为我们还没有捕获由WasRun.testBrokenMethod抛出的异常,并将其作为测试失败的结果记录到测试结果中。
完整示例代码
python
class TestResult:
def __init__(self):
self.runCount = 0
self.failureCount = 0
def testStarted(self):
self.runCount = self.runCount + 1
def testFailed(self):
self.failureCount = self.failureCount + 1
def summary(self):
return "%d run, %d failed" % (self.runCount, self.failureCount)
class TestCase:
def __init__(self, name):
self.name = name
def setUp(self):
pass
def tearDown(self):
pass
def run(self):
result = TestResult()
result.testStarted()
self.setUp()
try:
method = getattr(self, self.name)
method()
except:
result.testFailed()
self.tearDown()
return result
class WasRun:
def __init__(self, name):
self.name = name
self.wasRun = None
self.log = ""
def setUp(self):
self.wasRun = None
self.log = "setUp "
def testMethod(self):
self.wasRun = 1
self.log = self.log + "testMethod"
def tearDown(self):
self.log = self.log + " tearDown"
def testBrokenMethod(self):
raise Exception
class TestCaseTest(TestCase):
def testFailedResult(self):
test = WasRun("testBrokenMethod")
result = test.run()
assert "1 run, 1 failed" == result.summary()
本章小结
回顾本章内容,我们完成了以下重要任务:
- 编写了一个伪实现,并逐步将其完善,以变量代替常量来准确记录测试运行的相关信息。
- 编写了针对测试功能的测试用例,即测试的测试,用于验证测试框架的正确性。
- 针对测试运行失败的情况编写了专门的测试用例,虽然目前还存在异常捕获的问题,但为后续完善测试框架指明了方向。
通过不断地深入研究和实践,我们对xUnit测试框架的理解更加全面,在测试驱动开发的道路上又迈进了一步。后续我们将继续探索如何更好地处理测试失败等情况,进一步提升测试框架的稳定性和可靠性。