• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

软件测试中单元测试小技巧

发布: 2009-10-29 15:22 | 作者: 网络转载 | 来源: 领测软件测试网 | 查看: 44次 | 进入软件测试论坛讨论

领测软件测试网

软件测试中单元测试小技巧

这篇文章描述了:

  • 单元测试的信任
  • 测试正确事件
  • 创建维护测试
  • 创建易读测试

 这些天有很多的关于单元测试的和在不同的场景下为他们的应用程序编写单元测试(起始于, 我们2005年六月的 MSDN?Magazine 中有关测试你的数据层的文章, Know Thy Code: Simplify Data Layer Unit Testing using Enterprise Services)的讨论。这些意味着有很多的开发者自言自语(或者对于他们的团队)到:“哎,我们也需要开始编写测试了!”因此他们开始编写单元测试上面的单元测试直到他们达到了一个测试自己已经成为问题的程度。或许维护他们是一个太过困难,花费太长时间,或者他们并没有足够的易读性以便于理解,更或者他们本身存在bugs有一点是能够使得我们的开发人员可以下定决心去做的,那就是: 花费他们宝贵的时间以用来改进提高他们的测试或者忽略其中的问题, 从而有效的甩掉那些艰苦的工作。而这些困难的原因仅仅是因为那些不熟练的写入单元测试。.在这篇文章中,我将为大家带来在过去一年多时间里我在开发,提供咨询和培训开发者等方面有总结出来的一些最重要的练习和试验。这些小的技巧可以帮助您写出更有效的,可维护,和鲁棒性更好的单元测试。同时我希望这些总结和忠告可以帮助您避免一些由于错误引起的大量的时间的消耗。

 本页内容
  单元测试的信任
  测试正确的事情
  创建维护测试
  创建易读性测试
  在你的设置方法中避免部分相关的代码
  总结

 单元测试的信任
  在这个部分,我将略述出一些最通用的信任,这些信任来自于在使用大量单元测试获得的好处和解释为什么这些信任通常不是必须真实的。然后我们会帮助您在您的工程中拥有这些信任。

 更加简单的跟踪Bug 当然这并不是必须的,那么您怎么知道您的测试是正确的? 是否存在在一些测试环节测试失败的情况?另外您又如何知道您的测试覆盖了系统中多少的代码量?是否测试到了程序中的错误,错误又在哪里等等的问题。

 当你在你的单元测试中发现了bug后又会发生什么事情哪?你会突然间得到很多与愿意错误的反馈,bug被发现,但是问题并不在你测试的代码中。你的测试的逻辑存在一个bug,因此测试失败了。这些bug也是您最难被检查出来的,因为您通常会去检查您的应用程序而不会去检测你的测试环节。在这部分中,我会展示给你如何确认大量的单元测试,事实上就是使得跟踪bug变得更加容易。

 代码更加便于维护 从最终点考虑,你可以倾向于认为这些信任并不是必须的,当然你是对的,让我们去说,代码中每个逻辑方法至少要有一个测试方法(当然,你可能拥有一个以上的方法)在一个好的测试覆盖的工程中,大概有百分之六十的代码是能够得到单元测试的,现在不得不考虑到测试也是要被维护的,如果针对一个复杂的逻辑方法你有20个测试,那么当你向这个方法添加一个参数时会发生什么事情哪?测试无法编译。当你修改了类的结构的时候同样会发生这样的事情。这时你突然发现为了能让你的应用程序继续工作你自己需要改变大量的测试。当然这会花费你大量的时间。

 为了使这个信任确认下来,你需要确认你的测试是便于维护的。保持DRY规则写入:不要重复你自己。我们将更加接近的来看这个问题。

 代码更加容易被理解 单元测试的好处通常并非是人们最初所期待的,在一个工程中考虑修改一些你之前从没有看过的代码(比方说,一个特殊的类或者方法).你将如何动手处理这些代码?你可能需要在项目中去浏览这些特定的类或者方法使用的代码,理所当然,单元测试就是这样例子的一个很好的场所。同时,当正确写入的时候,单元测试可以为工程提供一个API文件的容易读取的设置,使得文档的处理和代码的理解对于整个团队中的新老开发者一样的简单,便捷。然而,这些只能在测试是易读的和容易理解的情况下才能被确认,这个规则很多的单元测试开发者并不会遵循。我将详述这个信任,然后在这篇文章的易读测试的部分给你展现如何在去写易读的单元测试。

 返回页首

  测试正确的事情
  新来者在Test Driven Development (TDD)中一个最通常的错误就是他们通常会搞混"Fail by testing something illogical."中的"Fail first"要求。例如,你可以用下面的规格开始这个方法:

' returns the sum of the two numbers
Function Sum(ByVal a As Integer, ByVal b As Integer) As Integer

 你可以向如下的方式写一个失败测试

<TestMethod()> _
Public Sub Sum_AddsOneAndTwo()
Dim result As Integer = Sum(1, 2)
Assert.AreEqual(4, result, "bad sum");
End Sub

 初看上去这个处理像是一个写失败测试的好的方法,它完全错失了你写错误测试的初始点。

 一个失败测试验证了在代码中存在一些错误,当你的测试完成后这个测试应该是通过的,现在的例子中,无论如何,测试都将会失败,即使是代码完成,因为测试逻辑上不是正确的。如果希望测试通过测需要测试自身进行修改――而不是程序的代码的改变(当程序代码改变的时候,是test-first规划的意图)简短来说,这个测试不会反映出程序代码完成后的最终的结果,因此这个不是一个好的测试。

 TDD中一个好的测试要求你去修改代码,从而使它能够按照想要的方式工作,这一点要胜于强迫你去反映现在的真实情况或者一个非逻辑要求的渴望的结果。例如,当1+1返回0时就意味着测试失败。这个简单的例子和这种情况是相似的,在练习中,如果现在的需求是在工作的,测试应该可以反映你所期待的结果,然后你可以调整现在代码的情况去通过这个测试。

 作为一个规则,一个已经调通的测试不应该被移除掉,因为这个测试在维护工作中可以用于恢复测试。他们在你改变代码时用来确定你没有损害到现在已经工作的函数。这就是为什么你不应该修改那些已经通过的测试,除非是一些很小的修改,例如增加它的可读性(换句话说,分解测试)

 当一个测试非正常失败 有时你可能遇到失败的测试,而这时你对代码的改变是完全合理的。这通常是因为你遇到了冲突的需求。一般来说,可能是一个新的需求(一个改变的特性)与一个旧的可能已经不再有效的需求发生了冲突。这有两种可能:

 1.在旧的需求或者无效或者在别处测试的情况下删除被验证本质上不再有效的失败的测试

  2.改变旧的测试使你可以测试新的要求(本质上使用新的测试),然后在新的设置下(测试的逻辑状态相同,但是初始功能函数可能有所不同)测试旧的需求。

  而有时候一个测试在使用不完整的技术去完成任务的时候也是有效的,例如,你有一个成员类带有一个FOO方法,它表现为某几种行为,它已经经由Test在X年前测试完成,然后现在一些其他的需求加了进来,方法的逻辑增强了,从而可以去处理一些类似于在获取数据时丢失一些参数的异常处理。但这时,突然Test X失败了,虽然在测试这个函数的时候只是使用了同样的类。这个测试的失败是因为在调用方法之前丢失了一些初始处理步骤。

 这并不意味着你需要移除Test X,你将丢失对于一些重要功能的测试,这时你应该去关心那些初始化时的问题,而不是改变类的创建以用来适应你新的意图。

 当然如果你那里有200个测试都是因为旧的结构导致的失败,你就应该找到这个问题来维护你的测试。这就是为什么你应该总是移除你测试中的副本尤其是在生产代码中。

 测试覆盖和测试Angles 你如何知道是否你的新代码是一个好的覆盖?当试图移动一个链接或者一个约束检查后,如果所有的测试依然通过,那么你就没有足够的代码复制然后你可能需要添加其他的测试单元。

 确认你添加正确测试的最好方法就是测试一些最平常的行和检查直到用非常的手段使它出错。这个也许很难,但是如果你不能考虑出一个让代码出错的方法,你就可能没有好的理由在最初的地方写下这行代码。

 你不知道什么时候下一个开发者会试图运行你的程序,他可能优化或者错误的删除一些包含本质的行。如果你没有一个测试,它就会失败,其他的开发者可能不会知道他们犯了错误。

 你也可能试图利用一些常量去替代一些已经通过了的测试中调用的各种各样的参数,例如,看下面的方法:

Public Function Sum(ByVal x As Integer, ByVal y As Integer, _
ByVal allowNegatives As Boolean) As Integer
If Not allowNegatives Then Throw New Exception()
Return x + y
End Function

 你可以打乱代码去测试覆盖,这有一些关于如何测试的变化:

' Try this...
If Not True Then ' replace flag with const
If x < 0 OrElse y < 0 Then Throw New Exception()
End If

' Or this...
If Not allowNegatives Then
' replace check with const
If False OrElse y < 0 Then Throw New Exception()
End If

 如果所有的测试依然通过,那么你缺少了一个测试,另外一个红色标志是在你为多种相同值测试的检查。如下:

 Assert.AreEqual(3, retval)

 一些方法的关系只看一次(在一个测试中)意味着你可以安全的返回3作为一个值,然后所有的针对这个方法的测试都将通过,这个当然意味着你丢失了一个测试。如果你在单元测试中检查一下代码,它就很容易被检查出来。

 确保你的测试写的越简单越好,一个单元测试一般不包括一个if switch或者其他任何的逻辑声明。如果你发现你自己在你的测试中写了一些类似于逻辑声明的东西,这是一个好的机会来测试一个以上的事件,在做这样的操作的时候,你会使得你的测试比读和维护更加的困难,在生产代码中同样如此。保持你的测试简单,你在生产代码中发现bug要胜于在你的单元测试中。

 使测试易于运行 如果你的测试并不容易运行,那么人们不会信任它。你的应用程序最有可能有下面两种类型的测试:

 测试在没有任何配置的情况下平稳的运行(这种类型的测试,我们可以在任何的机器上,在代码的最终版上或者在源控制上测试,并且做到没有任何故障的测试)

  在运行前需要一些配置.

  第一种类型是你应该模仿的,第二种类型是你通常做的,尤其你如果你是一个新的单元测试。如果你发现你自己测试时有很多的特殊的需求,现在是正常的,但是重要的一点就是你要隔离出两个组让他们能够单独的去做测试。

 我们的想法是任意一个开发者都应该有能力修改和运行一些不需要设置特殊的配置的测试进行测试。如果这有一些测试需要在运行前有特殊的关注,开发者应该知道他们,然后他可以花一些时间学习这些测试的方法。因为很多的开发者比较的懒(当然,不是你),你可以设想,他们不会去做那些特殊的设置,相反,他们会让测试失败因为他们有更好的事情去做。

 当用户让测试失败时,他们开始考虑他们不能够信任这些测试了。很难说是否测试可以在一个中找到一个正式的bug或者只是一个错误的定位。开发者可能不明白为什么测试者会在一开始就执行失败。一旦他们不再信任你的测试,开发者将会停止运行它们,那么bug就会驻留在程序中,之后一连串的麻烦就来了。。。

 为了避免这件事情,确认你总是有一个组准备好了去测试,测试程序则是可以安全运行,可信任的。把那些属于配置挑战组的测试放到不同的文件夹,树或者工程中,同时标记特殊的说明指明他们在运行前需要做什么。完成这些后,开发者可以不投入时间去配置就开始测试工作。当他们有时间和需要时,他们也可以配置,运行更多的测试环节。

 

延伸阅读

文章来源于领测软件测试网 https://www.ltesting.net/

TAG: 单元 技巧 软件测试

21/212>

关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备2023014753号-2
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网