zoukankan      html  css  js  c++  java
  • Java知识积累——单元测试和JUnit(一)

        说起单元测试,刚毕业或者没毕业的人可能大多停留在课本讲述的定义阶段,至于具体是怎么定义的,估计也不会有太多人记得。我们的教育总是这样让人“欣慰”。那么什么是单元测试呢?具体科学的定义咱就不去关心了,其实每个写代码的人都在时刻进行着单元测试,除非你从来不验证自己写的代码能否达到预期目的,而是直接写完就完事儿了,连run一下都不进行。

        单元测试说的直白一点,就是验证写得一段代码是否正确,可能是一个类,可能是一个函数,甚至可能是一个循环。为了测试的方便,我们一般直接就在写好的可运行代码中直接进行测试,看到控制台输出了预想的结果或者抛出了异常。但是进入了公司,这样的测试方法极不专业也不不容易复现测试环境。那么可能需要专门写一个测试类,调用你想测试的代码单元,然后进行测试。但是这样每次都需要新建类,编写测试用例,相当之麻烦。

        说了这么多,福利来了。单元测试工具——JUnit。协助我们进行单元测试,提供诸多便利。下面介绍如何在Eclipse中利用JUnit进行单元测试。

    假如,我们编写了一个Calculator,提供一些简单的计算器功能。代码如下,故意留一些bug。

     1 package org.logback.test;
     2 
     3 public class Calculator {
     4     
     5     private static int result;
     6     // 静态变量,用于存储运行结果
     7 
     8     public void add(int n) {
     9 
    10     result = result + n;
    11 
    12     }
    13 
    14     public void substract(int n) {
    15 
    16     result = result - 1; //Bug: 正确的应该是 result = result-n
    17 
    18     }
    19 
    20     public void multiply(int n) {
    21 
    22     } // 此方法尚未实现
    23 
    24     public void divide(int n) {
    25 
    26     result = result / n;
    27 
    28     }
    29 
    30     public void square(int n) {
    31 
    32     result = n * n;
    33 
    34     }
    35 
    36     public void squareRoot(int n) {
    37 
    38     for (; ;) ; //Bug : 死循环
    39 
    40     }
    41 
    42     public void clear() { // 将结果清零
    43 
    44     result = 0;
    45 
    46     }
    47 
    48     public int getResult() {
    49 
    50     return result;
    51 
    52     }
    53 }

    那么要对这个类在现有开发程度下进行单元测试了,方法很简单,首先在该类所属的工程名上右键进入Properties。

    在弹出的Properties窗口,左侧选择Java Build Path,然后右侧选择Libraries标签卡,最后选择Add Library。

    在弹出的Add Library窗口中,选择JUnit点击Next,然后在下拉菜单中选择JUnit4,点击Finish。

    这样JUnit就被引入了项目的Libraries中,点击OK。在要进行测试的那个类上右键,选择new→JUnit Test Case。

    在弹出的新建窗口中按如下设置,具体含义稍后讲解

    这里可以选择将测试类放在专门的测试包中,并且给测试类起一个显而易见的名字。选择Next,然后进入了下图。

    此处是选择要测试的方法,假如我们只测试加减乘除4个方法,则勾选对应的4个方法,点击Finish。则自动生成了一个测试类,不过我们仍需对此类进行一定的修改,将该测试类最终修改为如下代码

     1 package org.logback.test;
     2 
     3 import static org.junit.Assert.*;
     4 
     5 import org.junit.After;
     6 import org.junit.AfterClass;
     7 import org.junit.Before;
     8 import org.junit.BeforeClass;
     9 import org.junit.Ignore;
    10 import org.junit.Test;
    11 
    12 public class CalculatorTest {
    13     
    14     private static Calculator example = new Calculator();
    15 
    16     @Before//在每个测试方法执行前先执行的方法
    17     public void setUp() throws Exception {
    18         example.clear();
    19     }
    20     
    21     @After//在每个测试方法执行后立刻执行的方法
    22     public void setDown(){
    23         System.out.println("over");
    24     }
    25     
    26     @BeforeClass //在类加载的时候调用的方法,必须public和static的,只调用一次
    27     public static void start(){
    28         System.out.println("start class");
    29     }
    30     
    31     @AfterClass //在类结束的时候调用的方法,必须public和static的,只调用一次
    32     public static void destory(){
    33         System.out.println("destory class");
    34     }
    35     
    36     @Test
    37     public void testAdd() {
    38         example.add(2);
    39         example.add(3);
    40         assertEquals(5, example.getResult());
    41     }
    42 
    43     @Test
    44     public void testSubstract() {
    45         example.add(10);
    46         example.substract(2);
    47         assertEquals(8, example.getResult());
    48     }
    49 
    50     @Ignore//因该方法暂未实现而忽略测试
    51     @Test
    52     public void testMultiply() {
    53         fail("Not yet implemented");
    54     }
    55 
    56     @Test
    57     public void testDivide() {
    58         example.add(8);
    59         example.divide(2);
    60         assertEquals(4, example.getResult());
    61     }
    62     
    63     @Test(timeout = 1000)//设置时间限制,单位是毫秒,超时即算测试失败
    64     public void testsquareRoot(){
    65         example.squareRoot(4);
    66         assertEquals(2, example.getResult());
    67     }
    68 
    69     @Test(expected = ArithmeticException.class)//测试是否能如期抛出该异常
    70     public void divideByZero(){
    71         example.divide(0);//除数为0,如能正确抛出异常,则测试通过,否则测试失败
    72     }
    73 }

    每个方法都有注释,以标明其具体用途。

    为了要测试Calculator的功能,所以需要先创建一个对应的实例,就如14行所做的那样。代码中出现了很多@开头的东西,下面简单介绍一下。以@开头的称为标注,是JDK1.5引入的特性,简介一下JUnit中常用的标注的含义:

    @Test 标注的方法为测试方法,包含属性timeout(用于设置时间限制,以毫秒为单位,超过限制时间,该测试则以失败返回)、expected(设置此处应该抛出的异常,如果真抛出了该异常,则测试成功,否则失败)

    @Before  标注的方法会在每个测试方法执行前先执行一次

    @After 标注的方法会在每个测试方法执行结束后执行一次

    @BeforeClass  标注的方法会在类加载的时候执行一次,且仅此一次,该方法必须是public和static的

    @AfterClass   标注的方法会在类销毁的时候执行一次,且仅此一次,该方法必须是public和static的

    @Ignore  标注的方法表示因为要测试的方法仍未实现而忽略测试

    @Parameters  标注的方法用于定义测试数据集合,一般用来给一个测试方法传递多组测试数据

     

    以上标注都是用来标注方法的,下面介绍两个用来标注类的:

    @RunWith(classname.class)  指定此测试采用什么运行器,如果不设置,则采用默认的运行器,就像我们上一个例子中那样。

    @Suite.SuiteClasses({

       TestClassName1.class,

       TestClassName2.class,

       ...

    })   打包测试,有时会遇到同一个类的测试类有很多个,逐个运行测试太麻烦了,那就通过这种方式将所有要运行的测试类一起运行。文章后面会给出例子。

    介绍完标注之后,再来看一下测试方法中用到的assertEquals的功能。该方法有两个参数,第一个是预期的值,第二个是传递给方法的结果,用以比对方法处理后的结果与预期是否一致,因此来返回测试是否成功还是失败。

    用之前的代码进行测试,步骤如下:

    在类中右键Run As → JUnit Test

    可以看到左侧JUnit标签出现如下图所示结果:

    最上方的深红色进度条,表示有测试方法返回失败。然后列出了6个测试方法,蓝色X表示预期与实际结果不相同,红色X表示超过了限制条件(此处是超时了,因为测试方法调用的方法里面有死循环),绿色√表示该测试方法成功,灰色/表示该测试方法被忽略。点击列表中对应的方法名时,下方Failure Trace会给出错误信息。

    上述例子是针对测试的方法不需要多组数据的情况。OK,今天先这么多!改天继续~

    PS: 我存在过,我遇见过,我失败过。 有些路,明明有坑却从没人放警示牌。有些事,明明是错的却没人去管。有些话,明明应该告诉后来人却没人去说。 既然没人做,那就我来吧。希望我曾经历过的挫折不再重现于后来人。希望传承能够不是只挂在嘴边。希望人模人样的“人”能够真正做人。
  • 相关阅读:
    图床_背景
    图床_摘要
    图床_二维码
    在ubuntu上搭建交叉编译环境---arm-none-eabi-gcc
    在ubuntu上搭建交叉编译环境---arm-none-eabi-gcc
    python的sqlalchemy框架
    python的sqlalchemy框架
    python的sqlalchemy框架
    python的sqlalchemy框架
    烂泥:centos6 yum方式升级内核
  • 原文地址:https://www.cnblogs.com/FlameRen/p/3042334.html
Copyright © 2011-2022 走看看