精华内容
下载资源
问答
  • Java单元测试总结

    千次阅读 2021-06-13 15:50:20
    文章目录概述单元测试概念测试项目单元测试工具JUnitMockitoSpringBoot测试总结 概述 关于为什么要做单元测试是老生常谈了,越是小公司越不重视单元测试,这是实践出来的最经济的做法。由于大部分人在小公司工作,...

    [版权申明] 非商业目的注明出处可自由转载
    博文地址:
    出自:shusheng007

    概述

    关于为什么要做单元测试是老生常谈了,越是小公司越不重视单元测试,这是实践出来的最经济的做法。由于大部分人在小公司工作,所以单元测试从来就没有被真正的重视起来过。大部分时候你写单元测试,不是你觉得它有用而是因为公司要求写。由于大公司部门以及项目协作很复杂,加上人力物力相对富裕,所以勉强可以推行下去,小公司这么搞就是在找死!

    本人最近被迫写了很多单元测试,所以在此总结一下相关的知识点,留作笔记

    本文基于SpringBoot项目

    单元测试概念

    我们首先要清楚的理解什么是单元测试?那个单元是啥?在Java中那个单元一般指一个类,也就是说我们的测试是着眼于单个类的,而不是一个流程.

    例如有如下代码:

    public Class1{
    	private Class2 c2;
        ...
    	public void method1(){
    	     ...
            String result = c2.method2();
        }
    }
    

    Class1依赖Class2,我们要给Class1写unit test的时候怎么办呢?因为UT的思想是看当前单元的功能是否正常而不管其他单元。对应到这里的话就是,Class1的UT只测试Class1的方法method1是否正常工作,而不管Class2的方法method2的情况。如果你要管Class2的方法那就没头了,因为它也可能依赖其他类,以此类推,无穷无尽,最后就变成集成测试了。

    因为Class1的method1方法调用了Class2的方法,你不管怎么运行的通呢?答案就是Mock,让其按照我们的预期值通过。当然我们可以自己mock, 也可以使用框架帮助我们,这块Mockito开源库是当之无愧的扛把子。

    测试项目

    建立一个springboot的maven项目后,其会自动生成单元测试目录,如下所示

    在这里插入图片描述
    系统会生成一套与代码一致的测试目录结构

    spring boot会自动引入测试相关的依赖如下

     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
     </dependency>
    

    spring-boot-starter-test 会引入各种类库,其中就包括Junit和 Mockito。

    单元测试工具

    工欲善其事必先利其器,在Java的单元测试领域主流工具为JUnit与Mockito。JUnit 负责写单元测试业务逻辑,Mockito负责mock依赖。

    JUnit

    JUnit 已经发展到了JUnit5,所以我们只记录JUnit5的用法。

    JUnit5 包含3个部分:

    • JUnit Platform: 用于JVM上启动测试框架的基础服务,提供命令行,IDE和构建工具等方式执行测试的支持。

    • JUnit Jupiter:包含 JUnit 5 新的编程模型和扩展模型,主要就是用于编写测试代码和扩展代码。

    • JUnit Vintage:用于在JUnit 5 中兼容运行 JUnit3.x 和 JUnit4.x 的测试用例。

    编码相关的由 JUnit Jupiter 负责。

    写使用JUnit写单元测试非常简单,IDEA 内部甚至集成了JUnit,可以直接生成。

    例如我们有如下代码需要写单元测试

    public class Programmer {
        private final String content ="码字如飞";
        public String program(){
            return content;
        }
    }
    
    public class Company {
        private Programmer programmer;
        public Company(Programmer programmer) {
            this.programmer = programmer;
        }
    
        //计算测试与程序员的总人数
        public int getTotalStuff(int testers, int programmers){
           if(testers<0||programmers<0){
                throw new InvalidParameterException("不可为负数");
            }
            return testers + programmers;
        }
    	//开始项目,依赖Programmer
        public void startProject(){
            System.out.println("开始项目");
           System.out.println(programmer.program());
        }
    }
    

    如果你使用IDEA的话,光标停在类名称上,点击Alt+Enter键,弹出菜单后选择Create Test,如下所示:

    在这里插入图片描述
    然后勾选上你要进行单元测试的方法,点击Ok按钮,IDEA就为你在相应的位置生成了单元测试的骨架代码。
    在这里插入图片描述
    生成的代码如下:

    class CompanyTest {
    
        @BeforeEach
        void setUp() {
        }
    
        @AfterEach
        void tearDown() {
        }
    
        @Test
        void getTotalStuff() {
        }
    
        @Test
        void startProject() {
        }
    }
    
    • @Test 表示那是一个单元测试方法
    • @BeforeEach 此方法在每个测试方法执行前都会执行
    • @AfterEach 此方法在每个测试方法执行后都会执行

    JUnit 还有很多其他注解,我们接下来会讲到几个。

    走到这一步立刻就会遇到另一个问题,单元测试测什么啊?单元测试的目的是验证你那个方法在各种情况下是否正常工作。一般可以分为算法测试和结果测试,算法测试是看你的方法是否按照预期的执行步骤执行了,而结果测试是看你的方法在给定输入时最终的输出是否符合预期。

    如果你的代码写的比较垃圾,一个方法承担了特别多的职责,里面到处是逻辑分支,那么你这个方法进行算法测试就会非常空难,因为你要验证各个分支是否正常工作。

    我们接下来尝试为下面的方法书写单元测试

    public int getTotalStuff(int testers, int programmers){
        if(testers<0||programmers<0){
            throw new InvalidParameterException("不可为负数");
        }
        return testers + programmers;
    }
    

    对于上面的方法,我们一般会验证两个地方。第一档参数不合法时候的情况,第二相加结果。

    class CompanyTest {
        private Company company;
        @BeforeEach
        void setUp() {
            System.out.println("每个方法之前执行");
            company = new Company(new Programmer());
        }
    
        @Test
        void getTotalStuff_InvalidParam() {
            int tester = -1;
            int programmer = 5;
            Assertions.assertThrows(InvalidParameterException.class, () -> company.getTotalStuff(tester, programmer));
        }
    
        @DisplayName("获取员工数成功方法")
        @Test
        void getTotalStuff_Success() {
            int tester = 1;
            int programmer = 5;
            Assertions.assertEquals(6, company.getTotalStuff(tester, programmer));
        }
    
    
        @Disabled
        @Test
        void startProject() {
            System.out.println("startProject");
        }
    }
    

    @DisplayName("获取员工数成功方法") 将修改测试方法在测试报告中的名称,如下图所示。通过@Disabled可以屏蔽某个测试方法。
    在这里插入图片描述

    JUnit 提供了Assertions类,里面有很多断言的静态方法,例如本例中断言抛异常和相等的方法。

    关于JUnit更进一步的使用,这里推荐一个非常好的教程 Unit Testing with JUnit 5 - Tutorial

    Mockito

    Mockito一般都会伴随着JUnit出现,那么不使用Mockito可以完成UT吗?当然可以。如果不可以的话在没有Mockito的时候人们怎么办呢?只是因为用了它使生活变的更简单了。

    例如本例,我们需要一个Company的对象怎么办呢?只能自己mock一个,使用Mockito的话就它就可以帮我们mock了,如下图:

    @ExtendWith(MockitoExtension.class)
    class CompanyTest {
        @Mock
        private Programmer programmer;
    
        @InjectMocks
        private Company company;
    
        
        @BeforeEach
        void setUp() {
            System.out.println("每个方法之前执行");
    //        company = new Company(new Programmer());
        }
    
    ...
    //    @Disabled
        @Test
        void startProject() {
            System.out.println("startProject");
            Mockito.when(programmer.program()).thenReturn("码字如飞");
            company.startProject();
        }
    }
    

    @ExtendWith(MockitoExtension.class)是JUnit5的一个扩展,使用了这个就可以直接使用@Mock去mock字段了。上面还出现了一个@InjectMocks,它的作用是将其修饰的类所依赖的mock的对象直接注入,例如

    Company 依赖Programmer,我们通过@Mock mock了一个programmer对象,通过@InjectMocks 将programmer注入到了campony里。

    然后我们使用了Mockito的when.thenReturn方法mock了programmer的program方法,使程序不至于真的去调用programmer的program方法。

    关于Mockito的进一步学习,推荐Unit tests with Mockito - Tutorial

    SpringBoot测试

    SpringBoot 提供了一套可以启动Spring 容器的测试框架(@SpringBootTest),不到必要时候不要使用,太慢。不过当我们要测试Controlor时就需要这种方式了。

    总结

    虽然单元测试看起来比实际上有用,但仍然属于高级程序员应该掌握的知识。为什么大公司需要单元测试呢?因为参与项目的人员多,部门之间交流相当困难,还存在大量菜逼程序员,时不时会遇到狗屎一样的代码… 有了单元测试至少可以快速的发现你动了程序要死给你看的那个地方…。

    暂时就说这么多吧,本文主要从宏观方面阐述了单元测试的一些方面… 等有精力整理一份具体的使用案例,不过意义不大,一则可以看官网,二则网上类似文章已经很多。

    GitHub源码地址:springboot-learn

    展开全文
  • java单元测试总结

    千次阅读 2017-03-12 17:49:56
    java单元测试(使用junit) http://www.cnblogs.com/feiweiwei/archive/2009/06/16/1024623.html  JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework),供Java开发人员...

    java单元测试(使用junit)

    http://www.cnblogs.com/feiweiwei/archive/2009/06/16/1024623.html
        JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework),供Java开发人员编写单元测试之用。 


    1、概述 
      Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。 
      Junit本质上是一套框架,即开发者制定了一套条条框框,遵循这此条条框框要求编写测试代码,如继承某个类,实现某个接口,就可以用Junit进行自动测试了。 
      由于Junit相对独立于所编写的代码,可以测试代码的编写可以先于实现代码的编写,XP 中推崇的 test first design的实现有了现成的手段:用Junit写测试代码,写实现代码,运行测试,测试失败,修改实现代码,再运行测试,直到测试成功。以后对代码的修改和优化,运行测试成功,则修改成功。 
      Java 下的 team 开发,采用 cvs(版本控制) + ant(项目管理) + junit(集成测试) 的模式时,通过对ant的配置,可以很简单地实现测试自动化。 


      对不同性质的被测对象,如Class,Jsp,Servlet,Ejb等,Junit有不同的使用技巧,以后慢慢地分别讲叙。以下以Class测试为例讲解,除非特殊说明。 


    2、下载安装 


    去Junit主页下载最新版本3.8.1程序包junit-3.8.1.zip 


    用winzip或unzip将junit-3.8.1.zip解压缩到某一目录名为$JUNITHOME 


    将junit.jar和$JUNITHOME/junit加入到CLASSPATH中,加入后者只因为测试例程在那个目录下。 


    注意不要将junit.jar放在jdk的extension目录下 


    运行命令,结果如右图。 
    java junit.swingui.TestRunner junit.samples.AllTests 


    3、Junit架构 
      下面以Money这个类为例进行说明。 


    public class Money { 
    private int fAmount;//余额 
    private String fCurrency;//货币类型 


    public Money(int amount, String currency) { 
    fAmount= amount; 
    fCurrency= currency; 



    public int amount() { 
    return fAmount; 



    public String currency() { 
    return fCurrency; 



    public Money add(Money m) {//加钱 
    return new Money(amount()+m.amount(), currency()); 



    public boolean equals(Object anObject) {//判断钱数是否相等 
    if (anObject instanceof Money) { 
    Money aMoney= (Money)anObject; 
    return aMoney.currency().equals(currency()) 
    && amount() == aMoney.amount(); 

    return false; 




      Junit本身是围绕着两个设计模式来设计的:命令模式和集成模式. 


    命令模式 
      利用TestCase定义一个子类,在这个子类中生成一个被测试的对象,编写代码检测某个方法被调用后对象的状态与预期的状态是否一致,进而断言程序代码有没有bug。 
      当这个子类要测试不只一个方法的实现代码时,可以先建立测试基础,让这些测试在同一个基础上运行,一方面可以减少每个测试的初始化,而且可以测试这些不同方法之间的联系。 
      例如,我们要测试Money的Add方法,可以如下: 
    public class MoneyTest extends TestCase { //TestCase的子类 
    public void testAdd() { //把测试代码放在testAdd中 
    Money m12CHF= new Money(12, "CHF"); //本行和下一行进行一些初始化 
    Money m14CHF= new Money(14, "CHF"); 
    Money expected= new Money(26, "CHF");//预期的结果 
    Money result= m12CHF.add(m14CHF); //运行被测试的方法 
    Assert.assertTrue(expected.equals(result)); //判断运行结果是否与预期的相同 




      如果测试一下equals方法,用类似的代码,如下: 
    public class MoneyTest extends TestCase { //TestCase的子类 
    public void testEquals() { //把测试代码放在testEquals中 
    Money m12CHF= new Money(12, "CHF"); //本行和下一行进行一些初始化 
    Money m14CHF= new Money(14, "CHF"); 


    Assert.assertTrue(!m12CHF.equals(null));//进行不同情况的测试 
    Assert.assertEquals(m12CHF, m12CHF); 
    Assert.assertEquals(m12CHF, new Money(12, "CHF")); // (1) 
    Assert.assertTrue(!m12CHF.equals(m14CHF)); 




      当要同时进行测试Add和equals方法时,可以将它们的各自的初始化工作,合并到一起进行,形成测试基础,用setUp初始化,用tearDown清除。如下: 
    public class MoneyTest extends TestCase {//TestCase的子类 
    private Money f12CHF;//提取公用的对象 
    private Money f14CHF; 


    protected void setUp() {//初始化公用对象 
    f12CHF= new Money(12, "CHF"); 
    f14CHF= new Money(14, "CHF"); 

    public void testEquals() {//测试equals方法的正确性 
    Assert.assertTrue(!f12CHF.equals(null)); 
    Assert.assertEquals(f12CHF, f12CHF); 
    Assert.assertEquals(f12CHF, new Money(12, "CHF")); 
    Assert.assertTrue(!f12CHF.equals(f14CHF)); 



    public void testSimpleAdd() {//测试add方法的正确性 
    Money expected= new Money(26, "CHF"); 
    Money result= f12CHF.add(f14CHF); 
    Assert.assertTrue(expected.equals(result)); 




      将以上三个中的任一个TestCase子类代码保存到名为MoneyTest.java的文件里,并在文件首行增加 
    import junit.framework.*; 
    ,都是可以运行的。关于Junit运行的问题很有意思,下面单独说明。 
      上面为解释概念“测试基础(fixture)”,引入了两个对两个方法的测试。命令模式与集成模式的本质区别是,前者一次只运行一个测试。 


    集成模式 
      利用TestSuite可以将一个TestCase子类中所有test***()方法包含进来一起运行,还可将TestSuite子类也包含进来,从而行成了一种等级关系。可以把TestSuite视为一个容器,可以盛放TestCase中的test***()方法,它自己也可以嵌套。这种体系架构,非常类似于现实中程序一步步开发一步步集成的现况。 
      对上面的例子,有代码如下: 
    public class MoneyTest extends TestCase {//TestCase的子类 
    .... 
    public static Test suite() {//静态Test 
    TestSuite suite= new TestSuite();//生成一个TestSuite 
    suite.addTest(new MoneyTest("testEquals")); //加入测试方法 
    suite.addTest(new MoneyTest("testSimpleAdd")); 
    return suite; 




      从Junit2.0开始,有列简捷的方法: 
    public class MoneyTest extends TestCase {//TestCase的子类 
    .... 
    public static Test suite() {静态Test 
    return new TestSuite(MoneyTest.class); //以类为参数 




      TestSuite见嵌套的例子,在后面应用案例中有。    


    4、测试代码的运行 
      先说最常用的集成模式。 
      测试代码写好以后,可以相应的类中写main方法,用java命令直接运行;也可以不写main方法,用Junit提供的运行器运行。Junit提供了textui,awtui和swingui三种运行器。 
      以前面第2步中的AllTests运行为例,可有四种: 


    java junit.textui.TestRunner junit.samples.AllTests 
    java junit.awtui.TestRunner junit.samples.AllTests 
    java junit.swingui.TestRunner junit.samples.AllTests 
    java junit.samples.AllTests 


      main方法中一般也都是简单地用Runner调用suite(),当没有main时,TestRunner自己以运行的类为参数生成了一个TestSuite. 
       
      对于命令模式的运行,有两种方法。 


    静态方法 


    TestCase test= new MoneyTest("simple add") { 
    public void runTest() { 
    testSimpleAdd(); 

    }; 


    动态方法 


    TestCase test= new MoneyTest("testSimpleAdd"); 


      我试了一下,好象有问题,哪位朋友成功了,请指点我一下。确实可以。 


    import junit.framework.*; 


    public class MoneyTest extends TestCase {//TestCase的子类 
    private Money f12CHF;//提取公用的对象 
    private Money f14CHF; 
    public MoneyTest(String name){ 
    super(name); 

    protected void setUp() {//初始化公用对象 
    f12CHF= new Money(12, "CHF"); 
    f14CHF= new Money(14, "CHF"); 

    public void testEquals() {//测试equals方法的正确性 
    Assert.assertTrue(!f12CHF.equals(null)); 
    Assert.assertEquals(f12CHF, f12CHF); 
    Assert.assertEquals(f12CHF, new Money(12, "CHF")); 
    Assert.assertTrue(!f12CHF.equals(f14CHF)); 



    public void testAdd() {//测试add方法的正确性 
    Money expected= new Money(26, "CHF"); 
    Money result= f12CHF.add(f14CHF); 
    Assert.assertTrue(expected.equals(result)); 

    // public static void main(String[] args) { 
    // TestCase test=new MoneyTest("simple add") { 
    // public void runTest() { 
    // testAdd(); 
    // } 
    // }; 
    // junit.textui.TestRunner.run(test); 
    // } 
    public static void main(String[] args) { 
    TestCase test=new MoneyTest("testAdd"); 
    junit.textui.TestRunner.run(test); 




    再给一个静态方法用集成测试的例子: 
    public static Test suite() { 
    TestSuite suite= new TestSuite(); 
    suite.addTest( 
    new testCar("getWheels") { 
    protected void runTest() { testGetWheels(); } 

    ); 


    suite.addTest( 
    new testCar("getSeats") { 
    protected void runTest() { testGetSeats(); } 

    ); 
    return suite; 



    5、应用案例 


    Junit Primer例程,运行如下: 
    java com.hedong.JunitLearning.Primer.ShoppingCartTest 


    Ant+Junit+Mailto实现自动编译、调试并发送结果的build.xml 


    JUnit实施,写得很棒,理解也深刻。例程运行如下: 
    java com.hedong.JunitLearning.car.testCarNoJunit 
    java junit.swingui.TestRunner com.hedong.JunitLearning.car.testCar 


    Junit与log4j结合,阿菜的例程运行: 
    cd acai 
    ant junit 


    6、一些问题 
      有人在实践基础上总结出一些非常有价值的使用技巧,我没有经过一一“测试”,暂列在此。 


    不要用TestCase的构造函数初始化Fixture,而要用setUp()和tearDown()方法。 


    不要依赖或假定测试运行的顺序,因为JUnit利用Vector保存测试方法。所以不同的平台会按不同的顺序从Vector中取出测试方法。不知3.8中是不是还是如此,不过它提供的例子有一个是指定用VectorSuite的,如果不指定呢? 


    避免编写有副作用的TestCase。例如:如果随后的测试依赖于某些特定的交易数据,就不要提交交易数据。简单的回滚就可以了。 


    当继承一个测试类时,记得调用父类的setUp()和tearDown()方法。 


    将测试代码和工作代码放在一起,一边同步编译和更新。(使用Ant中有支持junit的task.) 


    测试类和测试方法应该有一致的命名方案。如在工作类名前加上test从而形成测试类名。 


    确保测试与时间无关,不要依赖使用过期的数据进行测试。导致在随后的维护过程中很难重现测试。 


    如果你编写的软件面向国际市场,编写测试时要考虑国际化的因素。不要仅用母语的Locale进行测试。 


    尽可能地利用JUnit提供地assert/fail方法以及异常处理的方法,可以使代码更为简洁。 


    测试要尽可能地小,执行速度快。 


    把测试程序建立在与被测对象相同的包中 


    在你的原始代码目录中避免测试码出现,可在一个源码镜像目录中放测试码 


    在自己的应用程序包中包含一个TestSuite测试类 


    7、相关资源下载 
    以下jar包,我只是做了打包、编译和调试的工作,供下载学习之用,相关的权利属于原作者。 


    可运行例程.jar 


    Build.xml 


    阿菜的例程 


    Junit API 汉译(pdf) 


    8、未完成的任务 


    httpunit 


    cactus 


    将Junit用链接池测试 
    ========

    Eclipse中使用JUnit4进行单元测试具体操作

    http://blog.csdn.net/youtellido/article/details/49457525
    简述


    Eclipse使用的版本Eclipse Mars(4.5)
    JUnit是Java语言的单元测试框架
    junit3与junit4的区别 
    在junit3中,如果某个类是测试类,必须将其继承类TestCase,如果某个方法是测试方法,必须让这个方法以testXX开头,如果希望指定某个测试方法运行之前运行某个初始化方法,这个方法的名称必须是setUp,如果希望在某个测试方法运行之后运行某个释放资源的方法,这个方法的名称必须是tearDown。 
    在junit4中,一个POJO类就是一个测试类,测试方法通过@Test来标识,初始化方法通过@Before来标识,释放资源的方法通过@After来标识,但是为了让junit4的测试类在junit3中也可以使用,习惯于把初始化方法命名为setUp,释放资源的方法命名为tearDown。Test中的测试方法一般以Test来开始。其中标识为Before注解的方法,每次运行测试类,都会执行标识为@After与@Before的方法。 
    4.在junit4中提供了一个Assert的类,这个类中有大量的静态方法进行断言的处理,在junit3中由于继承了TestCase,这个TestCase就可以直接assert,而junit4中需要先引入Assert类。
    具体操作


    1.在Eclipse中新建一个工程TestUnit,如图 
    图1 
    2.编写一个测试类Number.Java 
    图2


    package test;


    public class Number {
        public int add(int a,int b){
            return a+b;
        }
        public int min(int a,int b){
            if(a>b){
                return a-b;
            }
            return b-a;
        }
    }


    3.选中类Number.java,右键New,选择JUnit Test Case,如图 
    图3
    4.在打开的New JUnit Test Case对话框中,按照如下图所示的方式选择配置,基本保持默认配置,如图 
    图4 
    5.Next,选择要测试的方法,这里全选,如图 
    图5 
    6.Finish,弹出添加JUnit4 Library的对话框,OK。 
    图6 
    7.之后生成NumberTest.java,如图 
    图7
    NumberTest.java


    package test;


    import static org.junit.Assert.*;


    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;


    public class NumberTest {


        @Before
        public void setUp() throws Exception {
        }


        @After
        public void tearDown() throws Exception {
        }


        @Test
        public void testAdd() {
            fail("Not yet implemented");
        }


        @Test
        public void testMin() {
            fail("Not yet implemented");
        }


    }


    以上是默认生成的测试框架,接下来我们就要给测试方法添加代码了。 
    8.更改代码如下


    package test;


    import static org.junit.Assert.*;


    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;


    public class NumberTest {
        private Number num;


        @Before
        public void setUp() throws Exception {
            num=new Number();
        }


        @After
        public void tearDown() throws Exception {
        }


        @Test
        public void testAdd() {
            int res=num.add(2, 3);
            assertEquals(5, res);
        }


        @Test
        public void testMin() {
            int res=num.min(8, 3);
            assertEquals(5, res);
        }


    }


    9.选中NumberTest.java,右键,Run As–>JUnit Test,得到测试结果,当前结果表示测试通过。如图 
    图8
    ========

    Java单元测试(Junit+Mock+代码覆盖率)

    http://www.cnblogs.com/AloneSword/p/4109407.html


    单元测试是编写测试代码,用来检测特定的、明确的、细颗粒的功能。单元测试并不一定保证程序功能是正确的,更不保证整体业务是准备的。


    单元测试不仅仅用来保证当前代码的正确性,更重要的是用来保证代码修复、改进或重构之后的正确性。


    一般来说,单元测试任务包括


    接口功能测试:用来保证接口功能的正确性。
    局部数据结构测试(不常用):用来保证接口中的数据结构是正确的
    比如变量有无初始值
    变量是否溢出
    边界条件测试
    变量没有赋值(即为NULL)
    变量是数值(或字符)
    主要边界:最小值,最大值,无穷大(对于DOUBLE等)
    溢出边界(期望异常或拒绝服务):最小值-1,最大值+1
    临近边界:最小值+1,最大值-1
    变量是字符串
    引用“字符变量”的边界
    空字符串
    对字符串长度应用“数值变量”的边界
    变量是集合
    空集合
    对集合的大小应用“数值变量”的边界
    调整次序:升序、降序
    变量有规律
    比如对于Math.sqrt,给出n^2-1,和n^2+1的边界
    所有独立执行通路测试:保证每一条代码,每个分支都经过测试
    代码覆盖率
    语句覆盖:保证每一个语句都执行到了
    判定覆盖(分支覆盖):保证每一个分支都执行到
    条件覆盖:保证每一个条件都覆盖到true和false(即if、while中的条件语句)
    路径覆盖:保证每一个路径都覆盖到
    相关软件
    Cobertura:语句覆盖
    Emma: Eclipse插件Eclemma
    各条错误处理通路测试:保证每一个异常都经过测试
    JUNIT
    JUnit是Java单元测试框架,已经在Eclipse中默认安装。目前主流的有JUnit3和JUnit4。JUnit3中,测试用例需要继承TestCase类。JUnit4中,测试用例无需继承TestCase类,只需要使用@Test等注解。


    Junit3


    先看一个Junit3的样例


    // 测试java.lang.Math  
    // 必须继承TestCase  
    public class Junit3TestCase extends TestCase {  
        public Junit3TestCase() {  
            super();  
        }  
        
            // 传入测试用例名称  
        public Junit3TestCase(String name) {  
            super(name);  
        }  
       
            // 在每个Test运行之前运行  
        @Override  
        protected void setUp() throws Exception {  
            System.out.println("Set up");  
        }  
            // 测试方法。  
            // 方法名称必须以test开头,没有参数,无返回值,是公开的,可以抛出异常  
            // 也即类似public void testXXX() throws Exception {}  
        public void testMathPow() {  
            System.out.println("Test Math.pow");  
            Assert.assertEquals(4.0, Math.pow(2.0, 2.0));  
        }  
       
        public void testMathMin() {  
            System.out.println("Test Math.min");  
            Assert.assertEquals(2.0, Math.min(2.0, 4.0));  
        }  
       
            // 在每个Test运行之后运行  
        @Override  
        protected void tearDown() throws Exception {  
            System.out.println("Tear down");  
        }  
    }  
     
    如果采用默认的TestSuite,则测试方法必须是public void testXXX() [throws Exception] {}的形式,并且不能存在依赖关系,因为测试方法的调用顺序是不可预知的。
    上例执行后,控制台会输出


    Set up  
    Test Math.pow  
    Tear down  
    Set up  
    Test Math.min  
    Tear down  
     
    从中,可以猜测到,对于每个测试方法,调用的形式是:


    testCase.setUp();  
    testCase.testXXX();  
    testCase.tearDown();     
     
    运行测试方法


    在Eclipse中,可以直接在类名或测试方法上右击,在弹出的右击菜单中选择Run As -> JUnit Test。
    在Mvn中,可以直接通过mvn test命令运行测试用例。
    也可以通过Java方式调用,创建一个TestCase实例,然后重载runTest()方法,在其方法内调用测试方法(可以多个)。


    TestCase test = new Junit3TestCase("mathPow") {  
            // 重载  
        protected void runTest() throws Throwable {  
            testMathPow();  
        };  
    };  
    test.run();  
     
    更加便捷地,可以在创建TestCase实例时直接传入测试方法名称,JUnit会自动调用此测试方法,如


    TestCase test = new Junit3TestCase("testMathPow");  
    test.run();  
     
    Junit TestSuite


    TestSuite是测试用例套件,能够运行过个测试方法。如果不指定TestSuite,会创建一个默认的TestSuite。默认TestSuite会扫描当前内中的所有测试方法,然后运行。
    如果不想采用默认的TestSuite,则可以自定义TestSuite。在TestCase中,可以通过静态方法suite()返回自定义的suite。


    import junit.framework.Assert;  
    import junit.framework.Test;  
    import junit.framework.TestCase;  
    import junit.framework.TestSuite;  
       
    public class Junit3TestCase extends TestCase {  
            //...  
        public static Test suite() {  
            System.out.println("create suite");  
            TestSuite suite = new TestSuite();  
            suite.addTest(new Junit3TestCase("testMathPow"));  
            return suite;  
        }  
    }  
     
    允许上述方法,控制台输出


    写道
    create suite
    Set up
    Test Math.pow
    Tear down
     
    并且只运行了testMathPow测试方法,而没有运行testMathMin测试方法。通过显式指定测试方法,可以控制测试执行的顺序。


    也可以通过Java的方式创建TestSuite,然后调用TestCase,如 


    // 先创建TestSuite,再添加测试方法  
    TestSuite testSuite = new TestSuite();  
    testSuite.addTest(new Junit3TestCase("testMathPow"));  
       
    // 或者 传入Class,TestSuite会扫描其中的测试方法。  
    TestSuite testSuite = new TestSuite(Junit3TestCase.class,Junit3TestCase2.class,Junit3TestCase3.class);  
       
    // 运行testSuite  
    TestResult testResult = new TestResult();  
    testSuite.run(testResult);  
     
    testResult中保存了很多测试数据,包括运行测试方法数目(runCount)等。


    JUnit4


    与JUnit3不同,JUnit4通过注解的方式来识别测试方法。目前支持的主要注解有:


    @BeforeClass 全局只会执行一次,而且是第一个运行
    @Before 在测试方法运行之前运行
    @Test 测试方法
    @After 在测试方法运行之后允许
    @AfterClass 全局只会执行一次,而且是最后一个运行
    @Ignore 忽略此方法
    下面举一个样例:


    import org.junit.After;  
    import org.junit.AfterClass;  
    import org.junit.Assert;  
    import org.junit.Before;  
    import org.junit.BeforeClass;  
    import org.junit.Ignore;  
    import org.junit.Test;  
       
    public class Junit4TestCase {  
       
        @BeforeClass  
        public static void setUpBeforeClass() {  
            System.out.println("Set up before class");  
        }  
       
        @Before  
        public void setUp() throws Exception {  
            System.out.println("Set up");  
        }  
       
        @Test  
        public void testMathPow() {  
            System.out.println("Test Math.pow");  
            Assert.assertEquals(4.0, Math.pow(2.0, 2.0), 0.0);  
        }  
       
        @Test  
        public void testMathMin() {  
            System.out.println("Test Math.min");  
            Assert.assertEquals(2.0, Math.min(2.0, 4.0), 0.0);  
        }  
       
            // 期望此方法抛出NullPointerException异常  
        @Test(expected = NullPointerException.class)  
        public void testException() {  
            System.out.println("Test exception");  
            Object obj = null;  
            obj.toString();  
        }  
       
            // 忽略此测试方法  
        @Ignore  
        @Test  
        public void testMathMax() {  
              Assert.fail("没有实现");  
        }  
            // 使用“假设”来忽略测试方法  
        @Test  
        public void testAssume(){  
            System.out.println("Test assume");  
                    // 当假设失败时,则会停止运行,但这并不会意味测试方法失败。  
            Assume.assumeTrue(false);  
            Assert.fail("没有实现");  
        }  
       
        @After  
        public void tearDown() throws Exception {  
            System.out.println("Tear down");  
        }  
       
        @AfterClass  
        public static void tearDownAfterClass() {  
            System.out.println("Tear down After class");  
        }  
       
    }  
     
    如果细心的话,会发现Junit3的package是junit.framework,而Junit4是org.junit。
    执行此用例后,控制台会输出


    写道
    Set up before class
    Set up
    Test Math.pow
    Tear down
    Set up
    Test Math.min
    Tear down
    Set up
    Test exception
    Tear down
    Set up
    Test assume
    Tear down
    Tear down After class
     
    可以看到,执行次序是@BeforeClass -> @Before -> @Test -> @After -> @Before -> @Test -> @After -> @AfterClass。@Ignore会被忽略。


    运行测试方法


    与Junit3类似,可以在Eclipse中运行,也可以通过mvn test命令运行。


    Assert


    Junit3和Junit4都提供了一个Assert类(虽然package不同,但是大致差不多)。Assert类中定义了很多静态方法来进行断言。列表如下:


    assertTrue(String message, boolean condition) 要求condition == true
    assertFalse(String message, boolean condition) 要求condition == false
    fail(String message) 必然失败,同样要求代码不可达
    assertEquals(String message, XXX expected,XXX actual) 要求expected.equals(actual)
    assertArrayEquals(String message, XXX[] expecteds,XXX [] actuals) 要求expected.equalsArray(actual)
    assertNotNull(String message, Object object) 要求object!=null
    assertNull(String message, Object object) 要求object==null
    assertSame(String message, Object expected, Object actual) 要求expected == actual
    assertNotSame(String message, Object unexpected,Object actual) 要求expected != actual
    assertThat(String reason, T actual, Matcher matcher) 要求matcher.matches(actual) == true
    Mock/Stub
    Mock和Stub是两种测试代码功能的方法。Mock测重于对功能的模拟。Stub测重于对功能的测试重现。比如对于List接口,Mock会直接对List进行模拟,而Stub会新建一个实现了List的TestList,在其中编写测试的代码。
    强烈建议优先选择Mock方式,因为Mock方式下,模拟代码与测试代码放在一起,易读性好,而且扩展性、灵活性都比Stub好。
    比较流行的Mock有:


    JMock
    EasyMock
    Mockito
    powermock
    其中EasyMock和Mockito对于Java接口使用接口代理的方式来模拟,对于Java类使用继承的方式来模拟(也即会创建一个新的Class类)。Mockito支持spy方式,可以对实例进行模拟。但它们都不能对静态方法和final类进行模拟,powermock通过修改字节码来支持了此功能。


    EasyMock


    IBM上有几篇介绍EasyMock使用方法和原理的文章:EasyMock 使用方法与原理剖析,使用 EasyMock 更轻松地进行测试。
    EasyMock把测试过程分为三步:录制、运行测试代码、验证期望。
    录制过程大概就是:期望method(params)执行times次(默认一次),返回result(可选),抛出exception异常(可选)。
    验证期望过程将会检查方法的调用次数。
    一个简单的样例是: 


    @Test  
    public void testListInEasyMock() {  
        List list = EasyMock.createMock(List.class);  
        // 录制过程  
       
        // 期望方法list.set(0,1)执行2次,返回null,不抛出异常  
        expect1: EasyMock.expect(list.set(0, 1)).andReturn(null).times(2);  
        // 期望方法list.set(0,1)执行1次,返回null,不抛出异常  
        expect2: EasyMock.expect(list.set(0, 1)).andReturn(1);  
       
        // 执行测试代码  
        EasyMock.replay(list);  
            // 执行list.set(0,1),匹配expect1期望,会返回null  
        Assert.assertNull(list.set(0, 1));  
            // 执行list.set(0,1),匹配expect1(因为expect1期望执行此方法2次),会返回null  
        Assert.assertNull(list.set(0, 1));  
            // 执行list.set(0,1),匹配expect2,会返回1  
        Assert.assertEquals(1, list.set(0, 1));  
       
        // 验证期望  
        EasyMock.verify(list);  
    }  
     
    EasyMock还支持严格的检查,要求执行的方法次序与期望的完全一致。


    Mockito


    Mockito是Google Code上的一个开源项目,Api相对于EasyMock更好友好。与EasyMock不同的是,Mockito没有录制过程,只需要在“运行测试代码”之前对接口进行Stub,也即设置方法的返回值或抛出的异常,然后直接运行测试代码,运行期间调用Mock的方法,会返回预先设置的返回值或抛出异常,最后再对测试代码进行验证。可以查看此文章了解两者的不同。
    官方提供了很多样例,基本上包括了所有功能,可以去看看。
    这里从官方样例中摘录几个典型的:


    验证调用行为
    import static org.mockito.Mockito.*;  
       
    //创建Mock  
    List mockedList = mock(List.class);  
       
    //使用Mock对象  
    mockedList.add("one");  
    mockedList.clear();  
       
    //验证行为  
    verify(mockedList).add("one");  
    verify(mockedList).clear();  
     
     
    对Mock对象进行Stub
    //也可以Mock具体的类,而不仅仅是接口  
    LinkedList mockedList = mock(LinkedList.class);  
       
    //Stub  
    when(mockedList.get(0)).thenReturn("first"); // 设置返回值  
    when(mockedList.get(1)).thenThrow(new RuntimeException()); // 抛出异常  
       
    //第一个会打印 "first"  
    System.out.println(mockedList.get(0));  
       
    //接下来会抛出runtime异常  
    System.out.println(mockedList.get(1));  
       
    //接下来会打印"null",这是因为没有stub get(999)  
    System.out.println(mockedList.get(999));  
        
    // 可以选择性地验证行为,比如只关心是否调用过get(0),而不关心是否调用过get(1)  
    verify(mockedList).get(0);   
     
    代码覆盖率
    比较流行的工具是Emma和Jacoco,Ecliplse插件有eclemma。eclemma2.0之前采用的是Emma,之后采用的是Jacoco。这里主要介绍一下Jacoco。Eclmama由于是Eclipse插件,所以非常易用,就不多做介绍了。


    Jacoco


    Jacoco可以嵌入到Ant、Maven中,也可以使用Java Agent技术监控任意Java程序,也可以使用Java Api来定制功能。
    Jacoco会监控JVM中的调用,生成监控结果(默认保存在jacoco.exec文件中),然后分析此结果,配合源代码生成覆盖率报告。需要注意的是:监控和分析这两步,必须使用相同的Class文件,否则由于Class不同,而无法定位到具体的方法,导致覆盖率均为0%。


    Java Agent嵌入


    首先,需要下载jacocoagent.jar文件,然后在Java程序启动参数后面加上 -javaagent:[yourpath/]jacocoagent.jar=[option1]=[value1],[option2]=[value2],具体的options可以在此页面找到。默认会在JVM关闭时(注意不能是kill -9),输出监控结果到jacoco.exec文件中,也可以通过socket来实时地输出监控报告(可以在Example代码中找到简单实现)。


    Java Report


    可以使用Ant、Mvn或Eclipse来分析jacoco.exec文件,也可以通过API来分析。


    public void createReport() throws Exception {  
                // 读取监控结果  
        final FileInputStream fis = new FileInputStream(new File("jacoco.exec"));  
        final ExecutionDataReader executionDataReader = new ExecutionDataReader(fis);  
                // 执行数据信息  
        ExecutionDataStore executionDataStore = new ExecutionDataStore();  
                // 会话信息  
        SessionInfoStore sessionInfoStore = new SessionInfoStore();  
       
        executionDataReader.setExecutionDataVisitor(executionDataStore);  
        executionDataReader.setSessionInfoVisitor(sessionInfoStore);  
       
        while (executionDataReader.read()) {  
        }  
       
        fis.close();  
                   
                // 分析结构  
                final CoverageBuilder coverageBuilder = new CoverageBuilder();  
        final Analyzer analyzer = new Analyzer(executionDataStore, coverageBuilder);  
       
                // 传入监控时的Class文件目录,注意必须与监控时的一样  
        File classesDirectory = new File("classes");  
        analyzer.analyzeAll(classesDirectory);  
       
        IBundleCoverage bundleCoverage = coverageBuilder.getBundle("Title");  
                // 输出报告  
            File reportDirectory = new File("report"); // 报告所在的目录  
        final HTMLFormatter htmlFormatter = new HTMLFormatter();  // HTML格式  
        final IReportVisitor visitor = htmlFormatter.createVisitor(new FileMultiReportOutput(reportDirectory));  
                // 必须先调用visitInfo  
        visitor.visitInfo(sessionInfoStore.getInfos(), executionDataStore.getContents());  
        File sourceDirectory = new File("src"); // 源代码目录  
                // 遍历所有的源代码  
                // 如果不执行此过程,则在报告中只能看到方法名,但是无法查看具体的覆盖(因为没有源代码页面)  
        visitor.visitBundle(bundleCoverage, new DirectorySourceFileLocator(sourceDirectory, "utf-8", 4));  
                // 执行完毕  
        visitor.visitEnd();  
    }   
    ========

    菜鸟学Java(二十一)——如何更好的进行单元测试——JUnit



    测试在软件生命周期中的重要性,不用我多说想必大家也都非常清楚。软件测试有很多分类,从测试的方法上可分为:黑盒测试、白盒测试、静态测试、动态测试等;从软件开发的过程分为:单元测试、集成测试、确认测试、验收、回归等。


    在众多的分类中,与开发人员关系最紧密的莫过于单元测试了。像其他种类的测试基本上都是由专门的测试人员来完成,只有单元测试是完全由开发人员来完成的。那么今天我们就来说说什么是单元测试,为什么要进行单元测试,以及如更好的何进行单元测试。


    什么是单元测试?
    单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。比如我们可以测试一个类,或者一个类中的一个方法。


    为什么要进行单元测试?
    为什么要进行单元测试?说白了就是单元测试有什么好处,其实测试的好处无非就是减少bug、提高代码质量、使代码易于维护等。单元测试有什么好处请看一下百度百科中归纳的四条:


    1、它是一种验证行为。
    程序中的每一项功能都是测试来验证它的正确性。它为以后的开发提供支援。就算是开发后期,我们也可以轻松的增加功能或更改程序结构,而不用担心这个过程中会破坏重要的东西。而且它为代码的重构提供了保障。这样,我们就可以更自由的对程序进行改进。


    2、它是一种设计行为。
    编写单元测试将使我们从调用者观察、思考。特别是先写测试(test-first),迫使我们把程序设计成易于调用和可测试的,即迫使我们解除软件中的耦合。


    3、它是一种编写文档的行为。
    单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。


    4、它具有回归性。
    自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地的快速运行测试。


    如何更好的进行单元测试?


    在讨论如何更好的进行单元测试之前,先来看看我们以前是怎么测试代码的。
    以前是这样测试程序的:
    [java] view plain copy 在CODE上查看代码片派生到我的代码片
    public int add(int x,int y) {  
        return x + y;  
    }  
          
    public static void main(String args[]) {  
        int z = new Junit().add(2, 3);  
        System.out.println(z);  
    }  


    如上面所示,在测试我们写好的一个方法时,通常是用一个main方法调用一下我们要测试的方法,然后将结果打印一下。现在看来这种方式已经非常out了,所以出现了很多单元测试的工具,如:JUnit、TestNG等。借助它们可以让我们的单元测试变得非常方便、高效。今天就说说如何利用JUnit进行单元测试。


    我们新建一个Java Project以便进行演示,至于Java Project怎么创建我就不在此赘述了,如果连怎么建Java Project,那你还不适合看这篇文章。建好以后在该项目的“src”目录上右击,选择new——》JUnit Test Case,然后按下图填写必要信息:


    填写好包名和类名(选择New JUnit 4 Test),点击最下面的那个“Browse”按钮来选择需要测试的类:


    手动输入我们要测试的类,选择该类,点击“OK”,回到第一张图的界面,然后点击“Next”,来到下图:


    勾选要测试的方法,点击“Finish”,这样我们的JUnit测试实例就建好了。然后就可以写具体的测试了:


    package com.tgb.junit.test;  
      
    //静态引入  
    import static org.junit.Assert.*;  
    import static org.hamcrest.Matchers.*;  
      
    import org.junit.Test;  
      
    import com.tgb.junit.Junit;  
      
    public class JUnitTest {  
      
        @Test  
        public void testAdd() {  
            int z = new  Junit().add(2, 3);  
            assertThat(z , is(5));  
        }  
      
        @Test  
        public void testDivide() {  
            int z = new Junit().divide(4, 2);         
            assertThat(z, is(2));  
        }  
    }  


    写好以后,右击该类选择“Run As”——》“JUnit Test”,出现下图代表测试通过:


    到这里,可能有人会有疑问,JUnit跟用main方法测试有什么区别呢?
    首先,JUnit的结果更加直观,直接根据状态条的颜色即可判断测试是否通过,而用main方法你需要去检查他的输出结果,然后跟自己的期望结果进行对比,才能知道是否测试通过。有一句话能够很直观的说明这一点——keeps the bar green to keeps the code clean。意思就是说,只要状态条是绿色的,那么你的代码就是正确的。
    第二点,JUnit让我们同时运行多个测试变得非常方便,下面就演示一下如何进行多实例测试:
    首先我们要再建一个待测试类,然后再建一个对应的JUnit测试实例,步骤略。然后在我们测试实例的包上右击选择“Run As”——》“Run Configurations”,如下图;


    选择第二项“Run all tests in the selected project, package or source folder”,然后点击“Run”效果如下:


    可以看到,我们本次测试了两个类,共三个方法,这种方便的效果在测试实例越多的情况下,体现的越明显。至于main方法运行多个测试,想想就觉得非常麻烦,这里就不演示了。


    JUnit除了可以测试这些简单的小程序,还可以测试Struts、JDBC等等,这里只是用这个小程序做过简单的介绍。本实例使用的是hamcrest断言,而没有使用老的断言,因为hamcrest断言更加接近自然语言的表达方式,更易于理解。


    本实例需要引入以下三个jar包:
    hamcrest-core-1.3.jar
    hamcrest-library-1.3.jar
    junit-4.10.jar


    最后附上常用hamcrest断言的使用说明:
    [java] view plain copy 在CODE上查看代码片派生到我的代码片
    数值类型  
    //n大于1并且小于15,则测试通过  
    assertThat( n, allOf( greaterThan(1), lessThan(15) ) );  
    //n大于16或小于8,则测试通过  
    assertThat( n, anyOf( greaterThan(16), lessThan(8) ) );  
    //n为任何值,都测试通过  
    assertThat( n, anything() );  
    //d与3.0的差在±0.3之间,则测试通过  
    assertThat( d, closeTo( 3.0, 0.3 ) );  
    //d大于等于5.0,则测试通过  
    assertThat( d, greaterThanOrEqualTo (5.0) );  
    //d小于等于16.0,则测试通过  
    assertThat( d, lessThanOrEqualTo (16.0) );  
      
    字符类型  
    //str的值为“tgb”,则测试通过  
    assertThat( str, is( "tgb" ) );  
    //str的值不是“tgb”,则测试通过  
    assertThat( str, not( "tgb" ) );  
    //str的值包含“tgb”,则测试通过  
    assertThat( str, containsString( "tgb" ) );  
    //str以“tgb”结尾,则测试通过  
    assertThat( str, endsWith("tgb" ) );   
    //str以“tgb”开头,则测试通过  
    assertThat( str, startsWith( "tgb" ) );   
    //str忽略大小写后,值为“tgb”,则测试通过  
    assertThat( str, equalToIgnoringCase( "tgb" ) );   
    //str忽略空格后,值为“tgb”,则测试通过  
    assertThat( str, equalToIgnoringWhiteSpace( "tgb" ) );  
    //n与nExpected相等,则测试通过(对象之间)  
    assertThat( n, equalTo( nExpected ) );   
      
    collection类型  
    //map中包含key和value为“tgb”的键值对,则测试通过  
    assertThat( map, hasEntry( "tgb", "tgb" ) );  
    //list中包含“tgb”元素,则测试通过  
    assertThat( iterable, hasItem ( "tgb" ) );  
    //map中包含key为“tgb”的元素,则测试通过  
    assertThat( map, hasKey ( "tgb" ) );  
    //map中包含value为“tgb”的元素,则测试通过  
    assertThat( map, hasValue ( "tgb" ) );  
    ========

    java编程之单元测试(Junit)实例分析(附实例源码)

    http://www.jb51.net/article/74976.htm


    这篇文章主要介绍了java编程之单元测试(Junit),结合实例形式较为详细的分析总结了Java单元测试的原理、步骤及相关注意事项,并附带了完整代码供读者下载参考,需要的朋友可以参考下
    ..本文实例讲述了java编程之单元测试。分享给大家供大家参考,具体如下:


    完整实例代码代码点击此处本站下载。


    在有些时候,我们需要对我们自己编写的代码进行单元测试(好处是,减少后期维护的精力和费用),这是一些最基本的模块测试。当然,在进行单元测试的同时也必然得清楚我们测试的代码的内部逻辑实现,这样在测试的时候才能清楚地将我们希望代码逻辑实现得到的结果和测试实际得到的结果进行验证对比。


    废话少说,上代码:


    首先创建一个java工程,在工程中创建一个被单元测试的Student数据类,如下:
    package com.phicomme.hu;  public class Student  {   private String name;   private String sex;   private int high;   private int age;   private String school;   public Student(String name, String sex ,int high, int age, String school)   {    this.name = name;    this.sex = sex;    this.high = high;    this.age = age;    this.school = school;   }   public String getName()   {    return name;   }   public void setName(String name)   {    this.name = name;   }   public String getSex()   {    return sex;   }   public void setSex(String sex)   {    this.sex = sex;   }   public int getHigh()   {    return high;   }   public void setHigh(int high)   {    this.high = high;   }   public int getAge()   {    return age;   }   public boolean setAge(int age)   {    if (age >25)    {     return false;    }    else   {     this.age = age;     return true;    }       }   public String getSchool()   {    return school;   }   public void setSchool(String school)   {    this.school = school;   }  } 
    在eclipse下单元测试这个类:


    首先导入Junit包:选中java工程,点击鼠标右键--->选择properties---->在窗口中选Java Build Path---->在右侧点击Add Library---->在弹出的窗口列表中选中Junit---->下一步----->Junit 4(我用的是Junit 4)---->finish


    这样Junit 4包就导完了,接下来就是创建测试类:


    将测试类和被测试类放在不同的包中(也可以放在同一个包中,此处只是为了区别),代码如下:


    测试类1:


    package com.phicomme.test;  import com.phicomme.hu.Student;  import junit.framework.TestCase;  public class StudentTest01 extends TestCase  {   Student testStudent;   //此方法在执行每一个测试方法之前(测试用例)之前调用   @Override  protected void setUp() throws Exception   {    // TODO Auto-generated method stub    super.setUp();    testStudent = new Student("djm", "boy", 178, 24, "华东政法");    System.out.println("setUp()");   }   //此方法在执行每一个测试方法之后调用   @Override  protected void tearDown() throws Exception   {    // TODO Auto-generated method stub    super.tearDown();    System.out.println("tearDown()");   }   //测试用例,测试Person对象的getSex()方法   public void testGetSex()   {    assertEquals("boy", testStudent.getSex());    System.out.println("testGetSex()");   }   //测试Person对象的getAge()方法   public void testGetAge()   {    assertEquals(24, testStudent.getAge());    System.out.println("testGetAge()");   }  } 
    测试类2:


    package com.phicomme.test;  import junit.framework.TestCase;  import com.phicomme.hu.Student;  public class StudentTest extends TestCase  {   private Student testStudent;   @Override  protected void setUp() throws Exception   {    // TODO Auto-generated method stub    super.setUp();    testStudent = new Student("steven_hu", "boy", 170 , 23, "上海理工");   }   @Override  protected void tearDown() throws Exception   {    // TODO Auto-generated method stub    super.tearDown();   }   public void testSetage()   {    assertTrue(testStudent.setAge(21));   }   public void testGetSchool()   {    //预期值和实际值不一样,测试时出现失败(Failure)    assertEquals("南昌大学", testStudent.getSchool());   }   public void testGetName()   {    assertEquals("hdy", testStudent.getName());   }  } 
    当然,如果同时需要一起测试以上这两个测试类,可以通过TestSuite类实现,它相当于是一个套件,可以把所有测试类添进来一起运行测试;


    代码如下:


    package com.phicomme.test;  import com.phicomme.hu.StudentTest02;  import junit.framework.Test;  import junit.framework.TestSuite;  public class AllTest  {   //static PersonTest p = new PersonTest();   //static PersonTest p1 = new PersonTest();   public static Test suite()   {    TestSuite suite = new TestSuite("Test for com.phicomme.test");    //suite.addTest(p);    //suite.addTest(p1);    suite.addTestSuite(StudentTest.class);    suite.addTestSuite(StudentTest01.class);    return suite;   }  } 
    最后,分别测试以上三个类(选中需要测试的类---->鼠标右键---->Run As---->Junit Test):


    StudentTest类的测试结果图:


    StudentTest01类的测试结果图:


    AllTest类的测试结果图:


    有关java的测试就讲到这里,希望对大家有帮助,有时间也会接着讲讲有关android的单元测试,和在手机上实现编写一个UI界面替代eclipse如上图中的测试界面;


    ========
    展开全文
  • java单元测试总结.pdf

    2021-09-13 14:54:56
    java单元测试总结.pdf
  • JAVA 单元测试总结

    万次阅读 2017-01-10 12:42:29
    单元测试的重要性这里就不说了,直接进入正题。很多程序员不喜欢写单元测试,导致项目经常会花很多时间去debug,这完全得不偿失。对关键方法进行单元测试,可以在早期业务逻辑还没那么复杂的时候,尽快排除症结。在...

    单元测试的重要性这里就不说了,直接进入正题。很多程序员不喜欢写单元测试,导致项目经常会花很多时间去debug,这完全得不偿失。对关键方法进行单元测试,可以在早期业务逻辑还没那么复杂的时候,尽快排除症结。

    在dao,manager,server,web这样的分层项目中,通常单元测试是要写在server层的,因为server层可以测的最多。本文中不介绍单元测试的原理,只是介绍单元测试最常用的断言和Jmockit的用法,可以应付业务开发中绝大部分单元测试。

    首先添加maven依赖

    <dependencie>
        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.10</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-test</artifactId>
             <version>3.2.9.RELEASE</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.jmockit</groupId>
             <artifactId>jmockit</artifactId>
             <version>1.24</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-all</artifactId>
             <version>1.8.4</version>
             <scope>test</scope>
         </dependency>
    </dependencie>

    1 BaseTest.java

    server层新建test包,在IDEA中标记为绿色,这个里面写Before和After,如果不需要,就空在这里即可。其它具体的测试类要继承BaseTest.java。

    这里写图片描述

    package com.sf.sfpp.notice.test;
    
    import org.junit.After;
    import org.junit.Before;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "/test-service.xml" })
    public class BaseTest  extends AbstractTransactionalJUnit4SpringContextTests {
        @Before
        public void init(){
        }
        @After
        public void print(){
        }
    }

    2 assert断言

    使用assert断言是常用的单元测试方法之一。其本质是将方法的返回结果与预期值进行比较,相等则结果为绿色(单元测试通过),反之为红色(单元测试未通过)。

    比方说,我们在Manager层有一个类,UserHistoryManager,里面有个方法是根据ID删除用户操作历史

    @Autowired
    private UserHistoryMapper userHistoryMapper;
    
    public int deleteUserHistoryById(int userHistoryId){
        return userHistoryMapper.deleteUserHistoryById(userHistoryId);
    }

    现在想要对这个方法进行单元测试,在server层的test下面的impl文件夹中新建一个TestUserHistoryManager类,依旧如第一张图所示,代码如下:

    package com.sf.sfpp.notice.test.impl;
    
    import com.sf.sfpp.notice.common.domain.UserHistory;
    import com.sf.sfpp.notice.manager.UserHistoryManager;
    import com.sf.sfpp.notice.test.BaseTest;
    import org.junit.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    
    public class TestUserHistoryManager extends BaseTest {
        @Autowired
        private UserHistoryManager userHistoryManager;
    
        @Test
        public void testDeleteUserHistoryById(){
            Assert.assertEquals(true,userHistoryManager.deleteUserHistoryById(4) > 0);
        }
    }

    3 Jmockit

    有些方法要远远比上面的assert复杂,例如当你的方法中要添加一个对象到数据库中,此时如何进行单元测试呢?

    还是如第一张图片所示,在test下面的impl文件夹中新建TestUserNotificationManager.java,测试一下UserHistoryManager中添加用户历史的方法。

    package com.sf.sfpp.notice.test.impl;
    
    import com.sf.sfpp.notice.common.domain.UserHistory;
    import com.sf.sfpp.notice.manager.UserHistoryManager;
    import com.sf.sfpp.notice.test.BaseTest;
    import org.junit.Assert;
    import org.junit.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import static org.mockito.Mockito.mock;
    import static org.mockito.Mockito.when;
    
    public class TestUserNotificationManager extends BaseTest {
        @Autowired
        private UserHistoryManager userHistoryManager;
    
        @Test
        public void testAddUserHistory(){
            UserHistory userHistory = mock(UserHistory.class);
            when(userHistory.getAction()).thenReturn("balabala");
            when(userHistory.getTargetId()).thenReturn("balabala");
            when(userHistory.getUserId()).thenReturn(43);
            when(userHistory.getTargetKind()).thenReturn("balabala");
            when(userHistory.getId()).thenReturn("balabala");
            Assert.assertTrue(userHistoryManager.addUserHistory(balabala));
        }
    
    }
    

    上面的方法相当于用Jmockit虚拟了一个UserHistory对象(用户操作历史),然后根据其中的每个属性看返回值(字符串属性对应字符串返回值,int属性对应int返回值)。

    在IDEA中点击方法名前面的绿色箭头(ctrl+shift+F10)

    单元测试只要看到下面的绿色条,就表示测试通过了。
    这里写图片描述

    说明
    如有转载,请务必注明出处
    http://blog.csdn.net/antony9118/article/details/54312710

    展开全文
  • unittest单元测试框架总结 Java单元测试之JUnit篇
    展开全文
  • 在日常开发中离不开进行代码的测试,因此很有必要学会如何进行规范的单元测试 单元测试的好处: 1、提升软件质量 2、促进代码优化 3、提升研发效率 4、增加重构自信 单元测试基本原则:(AIR原则,必须用断言...
  • 虽然有三种主要类型的软件测试:单元测试,功能测试和集成测试,但是在这篇博文中,我们将讨论开发人员级单元测试。在我深入讲述具体细节之前,让我们先来回顾一下这三种测试的详细内容。 软件开发测试的类型 ...
  • jtest是parasoft公司推出的一款针对java语言的自动化白盒测试工具,它通过自动实现java单元测试和代码标准校验,来提高代码的可靠性。Jtest先分析每个java类,然后自动生成junit测试用例并执行用例,从而实现代码的...
  • Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法。目前支持的主要注解有: @BeforeClass 全局只会执行一次,而且是第一个运行@Before 在测试方法运行之前运行@Test 测试方法@After...
  • Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. 前言 以下内容为本人以开发人员的视角,在平时进行单元测试过程中的总结。主要内容为通用的...
  • 单元测试总结

    2014-11-21 13:07:06
    本文总结java和android中单元测试,方便...1、Java单元测试 1.1第一种方法 待测试类: package com.yqq.test; public class TestUnit { public int add(int x,int y){ return x+y; } } 主要是测试add方法的
  • 如何写Java单元测试

    千次阅读 2021-01-19 10:23:06
    什么是单元测试  我们在编写大型程序的时候,需要写成千上万个方法或函数,这些函数的功能可能很强大,但我们在程序中只用到该函数的一小部分功能,并且经过调试可以确定,这一小部分功能是正确的。但是,我们同时...
  • UT单元测试总结基础篇

    万次阅读 2018-03-11 22:01:11
    单元测试概念总结
  • 使用Mockito进行Java单元测试

    千次阅读 2016-12-27 22:57:27
    Google在3月份推出了一个关于Android MVP架构的官方Sample,除MVP架构本身之外,在这个Sample中配备了完善的单元测试用例,这对学习如何在Android中进行单元测试具有极高的价值。这篇文章主要是对其中使用的Mock框架...
  • Java单元测试经常需要构造各种测试数据,其中一项就是构造测试的字符串。 如果我们想要随机构造人名、地名、天气、学校、颜色、职业,甚至符合某正则表达式的字符串等,肿么办? 那么有一个库叫 java-fake 可以...
  • 最近项目有在写java代码的单元测试,然后在思考一个问题,为什么要写单元测试??单元测试写了有什么用??百度了一圈,如下: 软件质量最简单、最有效的保证;是目标代码最清晰、最有效的文档;可以优化目标代码...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 70,788
精华内容 28,315
关键字:

java单元测试总结

java 订阅