`
fly_ever
  • 浏览: 149768 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一种新的单元测试的方法

阅读更多
来自http://www.javalinux.it/wordpress/?p=116
个人很认同文章中的这个想法,因此翻译过来。不能保证翻译得正确,因此看原文还是更好的选择。
也希望各位能指出翻译中的错误,

     一种新的单元测试的方法意味着什么?难道说Junit或者TestNG还不够好?Junit(这里我提及到它因为它简单,但是在我的讨论中,TestNG也一样简单 from here on I’ll nominate it only for briefness,but TestNG is the same for my discussion)把测试类作为重点,并且所有的测试都是从那里开始。这意味着事实上,被测试类被认为仅仅存在于测试代码中,程序员只能通过它们使用的名字惯例来找到这些被测试类。

    在旧版本的Junit中,你设计的测试类,需要强制继承Junit框架中的类,并且将调用的方法需要用”test”开头。因此按这个惯例来命名测试类和测试方法,并把他们与被测试的类和方法“连接”起来。我想你会同意,TestNG和Junit4给了我们更多的自由,去掉这些要求。不管怎样,被测试的类和方法和我们的测试类仍然是这样逻辑的联系在一起,并且很多测试类仍然遵循那些旧的惯例。

     但是有很多更好的方式来命名类和方法!我来介绍BDD(Behaviour Driven Development),请注意BDD不是这篇文章的重点,但是它使我这篇文章更加完美。因此,让我们先用少许文字了解BDD吧。

BDD不仅是一个新的写测试的方法,也是一个按约定的新的设计形式
    引用behaviour-driven.org来开始我的介绍:
BehaviourDrivenDevelopment grew out of a thought experiment based on NeuroLinguisticProgramming techniques. The idea is that the words you use influence the way you think about something
BDD产生自一个基于神经语言规划学技术的实验的想法。这个想法是你用的语言会影响你考虑问题的方式。
     这个想法是需要程序员关注用来描述一个测试类或者方法的词语,因为所选的词语将影响到他们对这个问题的关注点。实际上,采用BDD方法写测试类时,相比这些被测试的类/方法本身,我们将更加关注这些被测试类/方法的行为。当然,这也将改变很多我们写测试代码的方式,比如,我们将对一个方法测试多次来验证每个行为是否正确。
     OK, what if I don’t believe on Neuro Linguistic Programming(神经语言规划学)?是否我还不相信神经语言规划学。好的,从一个纯粹的开发者角度来看,我们根据我们的类和方法的行为作为约定来命名测试,因此,这个测试结果将是绝对清晰的(比如,
”shouldAcceptNullValue fails”就是一个清楚的表达,并不需要复杂的报告)。让我们提供一个简单的例子:
@Test( expected = IllegalArgumentException.class )
    public void shouldNotPermitMethodNull() throws Exception {
    [..]
    }
    @Test( expected = IllegalArgumentException.class )
    public void shouldNotPermitEndPointNull() throws Exception {
    }
    @Test
    public void shouldInitWebParams() throws Exception {
    }
    @Test
    public void getHoldersResultShouldReturnHolderForRightParameters() throws Exception {
    }
    @Test
    public void getHoldersResultShouldIgnoreUnknowntParameters() throws Exception {
    }
    @Test
    public void getHoldersResultShouldIgnoreINParameters() throws Exception {
    }
    @Test
    public void shouldRuninvokeForOneWayMethod() throws Exception {
    }
    @Test
    public void shouldRuninvokeForMethods() throws Exception {
    }
    @Test
    public void shouldRuninvokeForMethodsApplyingMapping() throws Exception {
    }

    你需要一个简单的关于如何使用BDD成功应用到java上的介绍吗(最初的主意来自Ruby’s RSpec)?可以先看看excellent post.
那么BDD就够了吗?
    答案当然是no.BDD是很强大,你可以试一下,但是如果你真正的用于实践,你就会发现这些测试类和被测试类很快就会失去其联系。在BDD中,不仅仅测试方法不再是testXXX,那些测试类也可能不再是按约定取的名称。或者,你可能针对同一个被测试类/方法,会拥有多个测试的方法。例如之前的那个例子,当然不是很贴切,可能一个具体的测试类,比如来测试getHolder方法的行为的测试类更好一点。
你需要帮助吗?这是我的新的项目TestedBy
    通过注释来标注被测试类和方法,来使其与测试类和方法联系在一起,怎么样?不是太坏,你说呢?
我的想法或多或少从这里开始,但是不仅限于一个注释。我很高兴这个主意,因此我决定开始一个新的开源项目来提供测试工具,用来把被测试类放到中心的位置。
    继续看,我将展示给你如何通过注释和相关工具来改变你测试的方法。
    TestedBy目标在于改变观察测试类和被测试类的角度。我们可以把被测试的类(项目中最重要的类)放在中心位置,并可从这些类连接到他们的测试类和方法。一个代码快照可能抵得上更多的解释:
public class TestedBySample {
 
    /**
     * @param args
     */
    public static void main( String[] args ) {
        TestedBySample sample = new TestedBySample();
        System.out.print(sample.add(1, 2));
 
    }
 
    @TestedBy( testClass = "it.javalinux.testedby.TestedBySampleTest", testMethod = "addShouldWork" )
    public int add( int i,
                    int j ) {
        return i + j;
    }
    @TestedByList( {@TestedBy( testClass = "it.javalinux.testedby.TestedBySampleTest", testMethod = "addShouldWork" ),
        @TestedBy( testClass = "it.javalinux.testedby.TestedBySampleTest", testMethod = "addShouldWork2" )} )
    public int add2( int i,
                     int j ) {
        return i + j;
    }
 
}

    很好吧,但是它确实改变了你单元测试的方法?我觉得是,怎么样,至少在两个方面。
1,通过接口和约束来设计Design by interface and contracts
    软件设计中著名的词语说“Design by interface”,仍然在我耳边响起。因此你也当然可以“Test interface”。
很多正式的“Design by interface”意味着定义好你的接口,并且接着实现它们(可能大部分时间是由不同的人或者公司来实现)。总之,你能够影响到的只是如一个强类型语言,例如java能为你提供的那样:一个接口的实现必须遵循接口的签名,类型和参数变量保持一致。你不能控制到那些具体的行为。当然,这也是一个API设计上的一个很大的局限性,因为可能导致实现完全不可预期的行为。
    这里我就引出Eiffell language 和他的 design by contract (DbC)方法,约定来引导继承过来的特征的重新定义。在java中有很多工具支持Dbc,但是我的想法是我们已经有一个很强大的方式来测试方法上的约束,并且使用更少的代码来清楚行为:Unit Tests单元测试。
    使用TestedBy,测试在接口(或者父类)上声明,所有实现类都能运行这些测试,来验证这些实现类的行为,是符合父类类型上的行为和约束定义的。API设计者不仅提供接口,也提供一套验证该接口行为的测试类。因此每个实现者需要提供他们自己的实现,并且运行API设计者提供的测试,来保证实现类不仅是类型安全的,也是行为安全的。TestedBy传递给测试类一个被测试接口的实体类,并调用接口定义好的测试。
    这是一个使用TestedBy的例子:我们已经添加了@TestedBy注释在API接口,并提供一个@BeforeTestedBy注释来提供一个接口的实例。TestedBy将在实现类APIImplOne和APIImplTwo上运行shouldAddTwoAndThree,测试在第一个类上成功而在第二个类上失败。
public interface APIInterface {
   @TestedBy( testClass = "it.javalinux.testedby.APITest", testMethod = "shouldAddTwoAndThree" )
   public int add(int a, int b);
}
 
public class APIImplOne {
   public int add(int a, int b) {
	return a + b;
}
 
public class APIImplTwo {
   public int add(int a, int b) {
	return a - b;
}
 
public class APITest {
 
  private APIInterface instance;
 
  @BeforeTestedBy
  public beforeTestedBy(APIInterface instance) {
	this.instance = instance;
  } 	  
 
  public void shouldAddTwoAndThree() {
	assertThat(instance.add(3,2), is(5));
  }
 
}

    Of course I hava kept the example simple,but TestedBy has some more annotations ,for instance factory of classes under test can be specified when simple reflective invocation of no argument constructor isn’t enough。
    当然,我使例子尽量简单,但是TestedBy有更多的注释,比如当没有参数的构造函数的简单反射调用时,被测试类的实例工厂能被指定,这些注释还远远不够。
2,在当前工作的类上运行测试
    你写一个测试类来检验代码的正确性。很多时候,你写单元测试来保证代码的改变不会影响正在工作的代码,或者其他同事正在用的代码。你如何做呢?你可能改变你的代码,然后跑所有的涉及到修改的类的测试类。然后,最后你跑所有的测试来保证你没有影响到其他代码。
    那么让你的IDE第一步做什么呢?它编译你修改的类,并同时运行对应的测试类?既然你或者你的IDE能够运行测试类,testedBy让这个成为可能。一个eclipse插件就能做这些工作,针对你修改的类来运行相应的测试类,以验证没有破坏你的测试集,不仅仅是在编译阶段,也能在你写代码的时候。而且这个也不会太费时,因为插件能够根据TestedBy的注释来只运行很少的测试类,即那些已经修改过的类/方法对应的测试类。
    而且,运行测试类,能够得到一些清楚的报告比如:
"ClassUnderTest.methodUnderTest shouldThrowExceptionWithNullParameter doen't pass"

或者更好的:
"Failure: methodUnderTest in ClassUnderTest doesn't throw exception with null parameter, but it should!"

    当然,你能够拒绝这种针对类/方法名称 (如果你想的话)提供的便利,自己从整个工程中去找那些测试类,根据需要自己来测试。
    当然针对所有的类来运行所有的测试类也是可能的,你的测试也能够在Junit上运行,因为TestedBy是基于Junit测试的。
一些特点
让我列举在我心中TestedBy的特点吧:
1,第一个可能是最没有价值的,但是也是最有用的:在你的IDE中,你能够导航你的源代码到对应的测试代码。这个特性将在eclipse4.4的时候发布,它能够根据类名称导航,即使类名处在一个字符串中。当然,这只是一个开始,一个专门的eclipse插件将被开发用来导航代码,以及被测试代码的测试代码树形结构,针对打开/修改的类(见第3点)执行测试代码,等等。我不是一个eclipse开发的大师,因此非常欢迎哪位能够在这方面做出贡献。
2,你将在你的java文档中找到这些注释,考虑这是一个多好的事情,如果你使用BDD方式开发,定义测试方法形如shouldNotAcceptNull()或者shouldThrowsExceptionIfEmpty等等。使用BDD方法,事实上你能够定义和检查约束,通过使用TestedBy的注释,在JavaDoc文档中把这些展示给你的API用户。
3,你能够从被测试类开始运行测试,而不是测试类。我在之前就说过这些了。
4,通过接口和约束的设计。我已经在上文中专门介绍了这些。
5,测试类自动生成。一个工具(ant,maven,或者eclipse工具)能用我们的TestedBy注释来生成测试类。见6点。
6,Ant /maven 任务/插件来从被测试类运行测试,这个工具将管理并平稳的使用(用来保证测试类和注释间的同步将很重要):
    A,反转引擎:从存在的测试类开始,添加TestedBy注释到被测试类中。
    B,从TestedBy注释中开始运行测试类,来验证他们能运行所有的测试,并且没有注释指向不存在的测试。
    C,从注释开始生成(空的)测试类和方法。
    当然,这还不够,但是,我想这能给你一个想法。我现在正在做这些想法背后的事情,但是我需要在把他们呈现给社区之前把它们设计得更好。
Conclusions总结
     你对这个方法有兴趣吗?让我知道你的想法,并且跟你的朋友分享这个帖子…我能从这个帖子得到越多的反馈,我就能更好的做好它。

    现在问题是..目前这个项目的状态是什么?
你可以看一下project homepage on javalinuxlabs. googlecode 上面,你可以在svn下面找到一些类。这不是这个工程的第一次实现…它差不多是这个想法的证明。但是,我们需要更努力的工作来让它更快的派上用场。

    订购这个feeds.我将会经常发表声明,并且其他的回复也会关注这个想法,以使之得到不断的修正。
    你想贡献一份力量吗?看看this page来更好的理解我们需要哪些帮助。





分享到:
评论
13 楼 Durian 2009-06-19  
fly_ever 写道
其实就像guice通过annotation来连接接口和具体的实现类,
TestedBy也是希望通过annotation来连接测试类和被测试的类,
从而得到象guice那样的好处,能够更方便的跟踪代码。

----
小李飞刀的飞,小李飞刀的刀

用一个概念解释另一个概念,这是解释吗?
12 楼 shannon977 2009-06-19  
建议1:
@TestedByList还不够简单。关键词重复多次出现,就有压缩的余地。@TestedByList( {@TestedBy( testClass = "TestClass1", testMethod = "addShouldWork, addShouldWork2" ),  
        @TestedBy( testClass = "TestClass2", testMethod = "addShouldWork2, addShouldWork2" )} )
建议2
我不知在英文里是否有区别。但翻译的时候,为了以示区别,将annotation翻译成标记或许好些。这样我们就知道是@开头的一些东西。注释是/**/, //。不是大问题,但或可方便理解
11 楼 丁丁豆 2009-03-01  
from here on I’ll nominate it only for briefness,but TestNG is the same for my discussion
10 楼 fly_ever 2009-02-17  
其实就像guice通过annotation来连接接口和具体的实现类,
TestedBy也是希望通过annotation来连接测试类和被测试的类,
从而得到象guice那样的好处,能够更方便的跟踪代码。
9 楼 chensyaini 2009-02-17  
看不怎么懂!
8 楼 sunjiyun26 2009-01-06  
看不懂,但是真的希望有好的测试工具,使用越简单越好
7 楼 littleJava 2009-01-04  
给我的感觉就是,将测试类和被测试类通过注释绑定到一起了,能够更好的查找每个类相应的测试代码。  测试的开始是根据被测试的代码中的注释转到测试代码中,这个是方便了……!
6 楼 webee 2008-12-11  
有点意思。但是还要做的工作还是有的。 至少有各和junit的exlipse UI把!看不到绿色条,不够直观
5 楼 zhoujj303030 2008-11-27  
原来只听过Junit而且都还没有用过,现在又有什么这个东西看,发展的太快了啊!
4 楼 Jawfneo 2008-11-17  
有意思,不错。。
3 楼 seemoon 2008-11-17  
建议去看看rubyonrails的BDD,尤其是rspec,亲自写几段测试代码,java在这方面有些臃肿。
2 楼 pipilu 2008-11-04  
没看懂,不过,先了解一下behaviour-driven。
谢谢楼主分享!
1 楼 sinoyster 2008-10-27  
不错,学习了

相关推荐

    论文研究-一种针对单元测试框架的测试脚本重用方法.pdf

    通过对单元测试脚本的分析和自动翻译方法, 将原测试脚本中包含的信息提取出来, 解析为基于XML的中间脚本, 然后再利用XSLT技术, 依据XML记录的信息, 自动生成目标框架的单元测试脚本, 从而解决单元测试脚本的重用问题...

    一种FPGA的可编程逻辑单元的全覆盖测试方法.pdf

    一种FPGA的可编程逻辑单元的全覆盖测试方法.pdf

    C++单元测试三大框架的比较

    C++单元测试三大框架的比较软件测试1、TUT结构框架简单。添加新的测试工作量小;无须注册测试;可移植性好(因其只需两个头文件,就可以完成测试工作);便于装卸;提供接口可以扩展其输出方式等。最大的优点:轻量级,...

    软件测试中Junit单元测试实例

    上下文时间软件测试中Junit单元测试实例在一种传统的结构化编程语言中,比如C,要进行测试的单元一般是函数或子过程。在象C++这样的面向对象的语言中,要进行测试的基本单元是类。对Ada语言来说,开发人员可以选择是...

    软件测试质量保证:实验二 TestBed单元测试实验

    3、启动Testbed的单元测试模块(使用Unit Test only) 4、测试执行前准备:建立Sequence,配置Code Coverage,配置Test Environment。 5、创建测试用例 创建测试用例,右键点击被测函数名称即可弹出“Create New ...

    单元测试—NUnit测试

    元测试对程序员来说是非常...除了官方的解决方案之外,还有一种非常好的免费开源的第三方测试工具,那就是NUnit。它是从Java中著名的JUnit单元测试框架移植过来,这个可以从官网中得到答案,http://www.nunit.org/。

    Android单元测试-对Activity的测试

    上一篇文章已经介绍了单元测试的作用和简单示例,如果不了解的读者可以先阅读上一篇[ Android单元测试-作用以及简单示例](http://blog.csdn.net/double2hao/article/details/77159380)。 这篇文章主要介绍常见的...

    数据库操作的单元测试

    2. 数据库单元测试测试流程介绍 1 2.1. 数据库单元测试的原因 1 2.2. 测试关注点 1 2.3. 测试流程 1 3. 数据库单元测试最佳实践 2 3.1. 数据库单元测试最佳实践 2 3.1.1. 从“易测试的”应用程序体系结构开始。 2 ...

    单元测试工具C++Test简介

    Test简介单元测试工具C++Test简介软件测试C++Test是Parasoft公司出品的一个针对C/C++源代码进行自动化单元测试的工具。它可以对源代码进行三种测试:白盒测试、黑盒测试以及回归功测试。白盒测试C++Test对C/C++源...

    软件测试(单元测试)

    要求学生能够理解单元测试的相关概念和单元测试的过程、方法。3人一组。 【实验原理】 对给定的要求,采用白盒测试的方法进行单元测试,分别满足语句覆盖、判定覆盖、条件覆盖、条件组合覆盖、路径覆盖。 【实验...

    单元测试的总结

    作为WEB开发人员在开发过程中总是需要测试各种请求  常规的方法则是启动WEB服务器 测试 出错 ...今天给大家介绍一种不用启动WEB 直接采用单元测试的方法来测试请求是否准确  该方法基于SpringMVC 与 Spring Test 框架

    java eclipse 单元测试

    Java的junit 测试 单元测试的一种形式 可以测试一个或多个类的争取与否 在编写测试时需要穷举 但是也有一定的实用性

    软件测试之单元测试和自动化测试及UTF应用

    单元测试是一种自动化测试,它可以通过编写测试用例,执行代码,并验证代码的行为是否符合预期。在单元测试中,测试用例应该涵盖各种可能的输入和边界情况,以确保代码在所有情况下都能正确地运行。 单元测试是...

    一种针对单元测试框架的测试脚本重用方法 (2013年)

    通过对单元测试脚本的分析和自动翻译方法, 将原测试脚本中包含的信息提取出来, 解析为基于XML的中间脚本, 然后再利用XSLT技术, 依据XML记录的信息, 自动生成目标框架的单元测试脚本, 从而解决单元

    软件测试中的单元测试的组织方法

    单元测试的组织方法本文描述了三种单元测试的组织方法:自上而下法,自下而上法和分离法。组织方法是制定单元测试策略和拟制测试计划的关键因素;选择不适当的方法会对单元测试成本和软件维护开支造成不利影响。这里...

    计算机软件单元测试.doc

    该方法是一种综合的方法,目的是对软件单元进行系统化的测试,包括测试计划的执行、测试集的获取以及测试单元与其需求的对照衡量包括使用样本数据来执行被测试单元、并将该单元的实际结果与单元的需求文件中指定的...

    什么是 junit单元测试,及其作用.md

    **JUnit单元测试**是一种用于Java编程语言的单元测试框架,它可以帮助开发者编写和运行可重复的自动化测试,以验证代码中的各个单元(通常是一个类或方法)是否按照预期工作。单元测试是软件开发中的一个重要环节,...

    单元测试.pdf

    测试是一种验证我们的代码是否可以按预期工作的手段 被测的对象可以是我们程序的任何一个组成部分。大到一个氛围多步骤的下单流程,小到代码中的一个函数。 单元测试特指被测对象为程序中最小组成单元的测试,这里...

    电信设备-一种通信单元互换性测试系统及其互换方法.zip

    电信设备-一种通信单元互换性测试系统及其互换方法.zip

    电子-一种电子控制单元测试系统

    行业分类-电子-一种电子控制单元测试系统

Global site tag (gtag.js) - Google Analytics