51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 1681|回复: 1
打印 上一主题 下一主题

[讨论] Junit4 单元测试框架的常用方法介绍

[复制链接]
  • TA的每日心情
    无聊
    2023-12-19 11:16
  • 签到天数: 40 天

    连续签到: 1 天

    [LV.5]测试团长

    跳转到指定楼层
    1#
    发表于 2018-3-7 16:14:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    Junit 介绍:

    Junit是一套框架(用于JAVA语言),由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regres
    sion testing framework),即用于白盒测试。



    本文介绍的内容:

    1 Junit Myeclipse测试类的生成

    2 JUnit 4 常用的几个annotation 介绍与使用 (@Before  @After @Test @Ignore @BeforeClass @AfterClass)

    3 常用的断言介绍

    4 特殊的处理 (限时测试,异常测试)

    5 参数化配置 (@Parameters)



    准备测试代码

    测试的方法(正确、错误方法、死循环、抛异常)

    LogicService
    1. package com.logic;

    2. public class LogicService {
    3.    
    4.     public int add(int x ,int y){ //加法
    5.         return x+y;
    6.     }
    7.    
    8.     public int sub(int x ,int y){ //减法
    9.         return x-y;
    10.     }
    11.    
    12.     public int div(int x ,int y){ //除法
    13.         return x/y;
    14.     }
    15.    
    16.     public int div2(int x ,int y){ //除法  做了异常判断
    17.         try {
    18.             int z = x/y;
    19.         } catch (Exception e) {
    20.             e.printStackTrace();
    21.         }
    22.         return x/y;
    23.     }
    24.    
    25.     public void loop(int x ,int y){ //死循环
    26.         for(;;)
    27.             x=y;
    28.     }   
    29.    
    30.     public void unCompleted(int x ,int y){ //未完成的模块
    31.         //还在开发中
    32.     }
    33.    
    34. }
    复制代码
    一  Myeclipse测试类的生成

    1 对需要测试的类点右键 NEW 一个Junit Test Case

    2 点击NEXT

    注意 1 选择NEW Junit 4 test

            2 source folder 是默认会填写上之前右键NEW的那个类,如果不是的话,请自行进行修改

            3 package 默认会填写当前的包名 个人建议重新开个测试包-即在包后面加上.test 表示是单元测
    试用例专用包与源代码分离

            4 name 默认会在之前右键NEW的那个类的基础的后面加上Test 如果不是的话,建议自行进行
    修改,便于标示

            5 初始化的方法,我一般会勾上个setUp,这个请随意。

    3 继续点击NEXT

    1 这里可以选择需要测试的方法,我一般都是全选的然后在生成的测试类中再做处理

    2 点击finish完成

    1. 4 生成的单元测试类

    2. 复制代码
    3. package com.logic.test;

    4. import static org.junit.Assert.*;

    5. import org.junit.Before;
    6. import org.junit.Test;

    7. public class LogicServiceTest {

    8.     @Before
    9.     public void setUp() throws Exception {
    10.     }

    11.     @Test
    12.     public void testAdd() {
    13.         fail("Not yet implemented");
    14.     }

    15.     @Test
    16.     public void testSub() {
    17.         fail("Not yet implemented");
    18.     }

    19.     @Test
    20.     public void testDiv() {
    21.         fail("Not yet implemented");
    22.     }

    23.     @Test
    24.     public void testDiv2() {
    25.         fail("Not yet implemented");
    26.     }

    27.     @Test
    28.     public void testLoop() {
    29.         fail("Not yet implemented");
    30.     }

    31.     @Test
    32.     public void testUnCompleted() {
    33.         fail("Not yet implemented");
    34.     }

    35. }
    复制代码
    二 JUnit 4 常用的几个annotation 介绍与使用 (@Before  @After @Test @Ignore @BeforeClass @After
    Class)

    1 常用的annotation介绍

    @Before:初始化方法,在任何一个测试执行之前必须执行的代码;

    @After:释放资源,在任何测试执行之后需要进行的收尾工作。在每个测试方法执行之后执行一次,
    该annotation只能修饰public void 方法;

    @Test:测试方法,表明这是一个测试方法。在Junit中将会自动被执行。该annotation只你呢个修饰p
    ublic void 方法。

    @Ignore:忽略的测试方法,标注的含义就是“某些方法尚未完成,暂不参与此次测试”;

    @BeforeClass:针对所有测试,只执行一次,且必须为public static void;一般用于初始化必要的消耗
    较大的资源,例如数据库连接等

    @AfterClass:针对所有测试,将会在所有测试方法执行结束后执行一次,且必须为public static void;



    2 常用的annotation测试

    修改单元测试类LogicServiceTest
    1. package com.logic.test;

    2. import static org.junit.Assert.*;

    3. import org.junit.After;
    4. import org.junit.AfterClass;
    5. import org.junit.Before;
    6. import org.junit.BeforeClass;
    7. import org.junit.Ignore;
    8. import org.junit.Test;

    9. public class LogicServiceTest {

    10.     @Before
    11.     public void setUp() throws Exception {
    12.         System.out.println("@Before");//测试@Before
    13.     }

    14.     @After
    15.     public void end() throws Exception {
    16.         System.out.println("@After");//测试@@After
    17.     }

    18.     @BeforeClass
    19.     public static void init() throws Exception {
    20.         System.out.println("@BeforeClass");//测试@BeforeClass
    21.     }

    22.     @AfterClass
    23.     public static void disstroy() throws Exception {
    24.         System.out.println("@AfterClass");//测试@AfterClass
    25.     }

    26.     @Test
    27.     public void testAdd() {
    28.         System.out.println("@Test testAdd");//测试@Test
    29.     }

    30.     @Test
    31.     public void testSub() {
    32.         System.out.println("@Test testSub");//测试@Test
    33.     }

    34.     @Ignore
    35.     public void testDiv() {
    36.         System.out.println("@Ignore ");//测试@Ignore
    37.     }

    38.     @Ignore
    39.     public void testDiv2() {
    40.         System.out.println("@Ignore ");//测试@Ignore
    41.     }

    42.     @Ignore
    43.     public void testLoop() {
    44.         System.out.println("@Ignore ");//测试@Ignore
    45.     }

    46.    
    47.     public void testUnCompleted() {
    48.         System.out.println("@Ignore ");//测试未标注
    49.     }

    50. }
    复制代码
    执行结果


    执行结果分析

    1 @BeforeClass和@AfterClass只执行一次,在所有方法开始前/后

    2 @Before和@After在每个@Test标注的方法前后各执行一次

    3 @Test 标注的方法都会执行一次(表示要测试的方法)

    4 @Ignore方法不会被执行,没有annotation的方法也不会被执行

    5 总结  @BeforeClass –> (@Before –> @Test –> @After) –> @AfterClass



    理解了以上注解后就可以尝试着在日常的项目中使用Junit进行单元测试了。



    3 常用的断言介绍

    assertEquals(String msg, Object expectRes, Object Res) --------  用于值判断

    判断expectRes.equals(Res) ,表示值等于的判断,失败则抛MSG

    assertSame(String msg, Object expectRes, Object Res)  --------  用于地址判断

    判断expectRes==Res,表示地址等于的判断,失败则抛MSG

    assertTrue(String msg,Boolean result) ----------------------------用于Boolean判断

    判断result是true还是false,失败则抛MSG

    assertNull(String msg,Object result)-------------------------------用于NULL判断

    判断result是否为NULL,失败则抛MSG

    fail(String msg);---------------------------------------------------直接中止方法运行

    直接中止方法运行,抛出MSG



    测试代码
    1. package com.logic.test;

    2. import static org.junit.Assert.*;

    3. import org.junit.After;
    4. import org.junit.AfterClass;
    5. import org.junit.Before;
    6. import org.junit.BeforeClass;
    7. import org.junit.Ignore;
    8. import org.junit.Test;

    9. import com.logic.LogicService;

    10. public class LogicServiceTest {
    11.     LogicService logserv ;

    12.     @Before
    13.     public void setUp() throws Exception {
    14.         logserv = new LogicService();
    15.     }

    16.     @Test
    17.     public void testAdd() {
    18.         String a = "aa";
    19.         String t = "a";
    20.         String b = "a"+t;
    21.         assertEquals("assertEquals", a, b) ; //A与B的关系是值相等,地址不相等,这个用例会成功
    22.     }

    23.     @Test
    24.     public void testSub() {
    25.         String a = "aa";
    26.         String t = "a";
    27.         String b = "a"+t;
    28.         assertSame("assertSame", a, b) ; //A与B的关系是值相等,地址不相等,这个用例会失败
    29.     }

    30.     @Test
    31.     public void testDiv() {
    32.         assertTrue("assertTrue",true);//用例成功
    33.         assertTrue("第二个为false失败",false);//用例失败
    34.     }

    35.     @Test
    36.     public void testDiv2() {
    37.         assertNull("assertNull",null);//用例成功
    38.         assertNull("第二个为notNull失败","a");//用例失败
    39.     }

    40.     @Ignore
    41.     public void testLoop() {
    42.     }

    43.     @Ignore
    44.     public void testUnCompleted() {
    45.     }

    46. }
    复制代码
    执行结果分析

    这里我不再截图了

    1 成功

    2 失败,返回MSG为assertSame

    3 第一个成功,第二个失败,返回MSG为第二个为false失败

    4 第一个成功,第二个失败,返回MSG为第二个为notNull失败

    断言是用来判断被测方法执行的结果与预期结果是否匹配



    4 特殊的处理 (限时测试,异常测试)

    1 Junit提供限时处理的机制。

    @Test(timeout=1000) 单位毫秒


    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2023-12-19 11:16
  • 签到天数: 40 天

    连续签到: 1 天

    [LV.5]测试团长

    2#
     楼主| 发表于 2018-3-7 16:14:46 | 只看该作者
    当方法用时超过1000毫秒时,此方法会自动中止并执行失败
    package com.logic.test;

    import static org.junit.Assert.*;

    import org.junit.After;
    import org.junit.AfterClass;
    import org.junit.Before;
    import org.junit.BeforeClass;
    import org.junit.Ignore;
    import org.junit.Test;

    import com.logic.LogicService;

    public class LogicServiceTest {
        LogicService logserv ;

        @Before
        public void setUp() throws Exception {
            logserv = new LogicService();
        }

        @Ignore
        public void testAdd() {
        }

        @Ignore
        public void testSub() {
        }

        @Ignore
        public void testDiv() {
        }

        @Test(timeout=1000)
        public void testDiv2() {
            System.out.print("我不会超过1000毫秒的");
        }

        @Test(timeout=1000)
        public void testLoop() {
            logserv.loop(1, 1);//此方法使用的是死循环实现,所以一定会超过限时,超过限时后此方法会自动中止
        }

        @Ignore
        public void testUnCompleted() {
        }

    }
    执行结果

    loop方法超时报错,div2方法不超时成功



    2 Junit提供异常处理的机制。

    @Test(expected=Exception.class) 其中Exception.class可以写的更加具体

    测试
    @Test(expected=Exception.class)
        public void testDiv() {
            System.out.print(logserv.div(3, 0));
        }

        @Test(expected=Exception.class)
        public void testDiv2() {
            System.out.print(logserv.div(3, 0));
        }
    复制代码
    执行结果

    两个都通过



    测试

    复制代码
        @Test(expected=Exception.class)
        public void testDiv() {
            System.out.print(logserv.div(3, 0));
        }

        @Test
        public void testDiv2() {
            System.out.print(logserv.div(3, 0));
        }
    执行结果

    第一个通过 第二个不通过 异常为除数不能为zero



    5 参数化配置 (@Parameters)   重要

    进行单元测试的时候,通常一个方法需要好几个case进行测试,Junit提供参数化便于我们对方法进行
    多种参数的组合测试

    如果不使用参数化进行测试的话,那么我们的测试类会做的很臃肿

    例如
    @Test
        public void testAdd() {
            assertEquals("1+1 失败",2,logserv.add(1, 1) );
        }
        @Test
        public void testAdd1() {
            assertEquals("1+2 失败",3,logserv.add(1, 2) );
        }
        @Test
        public void testAdd2() {
            assertEquals("1+3 失败",3,logserv.add(1, 3) );
        }
        @Test
        public void testAdd3() {
            assertEquals("1+4 失败",3,logserv.add(1, 4) );
        }
    这样的测试类显然看起来不是很理想,代码过于重复



    参数化的实现过程(重要)

    1 在测试类上增加

    @RunWith(Parameterized.class)并引入

    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;

    2 写上构造类的函数及定义入参

    例如
    @RunWith(Parameterized.class)
    public class LogicServiceTest {
        LogicService logserv ;
        int parm1 ;//定义入参
        int parm2 ;//定义入参
        int res;//定义入参
       
       public LogicServiceTest(int parm1,int parm2,int res){//定义构造函数
           this.parm1=parm1;
           this.parm2=parm2;
           this.res=res;
       }
    3 定义一个返回结果为collection类型的方法并写上@Parameters

    注意 Arrays.asList()里面NEW的Object的要与定义的参数一一对应

    例如
    public class LogicServiceTest {
        LogicService logserv ;
        int parm1 ;//定义入参
        int parm2 ;//定义入参
        int res;//定义入参
       
       public LogicServiceTest(int parm1,int parm2,int res){//定义构造函数
           this.parm1=parm1;
           this.parm2=parm2;
           this.res=res;
       }
       
       @Parameters   
       public static Collection<Object[]> initParm(){
           return  Arrays.asList(new Object[][]{
              {1,1,2},{1,2,3},{1,3,4},{1,3,5}//{}里的参数一定要和构造函数一一对应
       });
       }
    4 编写测试方法,调用参数

    @Test
    public void testAdd() {
    assertEquals(res,logserv.add(parm1, parm2));
    }
    5 测试类代码全景(准备执行)

    复制代码
    package com.logic.test;

    import static org.junit.Assert.*;

    import java.util.Arrays;
    import java.util.Collection;

    import org.junit.Before;
    import org.junit.Ignore;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameters;

    import com.logic.LogicService;

    @RunWith(Parameterized.class)
    public class LogicServiceTest {
    LogicService logserv;
    int parm1;// 定义入参
    int parm2;// 定义入参
    int res;// 定义入参

    public LogicServiceTest(int parm1, int parm2, int res) {// 定义构造函数
    this.parm1 = parm1;
    this.parm2 = parm2;
    this.res = res;
    }

    @Parameters
    public static Collection<Object[]> initParm() {
    return Arrays.asList(new Object[][] { { 1, 1, 2 }, { 1, 2, 3 },
    { 1, 3, 4 }, { 1, 3, 5 } // {}里的参数一定要和构造函数一一对应
    });
    }

    @Before
    public void setUp() throws Exception {
    logserv = new LogicService();
    }

    @Test
    public void testAdd() {
    assertEquals(res, logserv.add(parm1, parm2));
    }

    @Ignore
    public void testSub() {
    }
    }
    复制代码
    6 执行结果

    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-4-25 10:18 , Processed in 0.066872 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表