JUnit测试 By Intellij IDEA15(2016.3)

JUnit单元测试的基本使用

我们使用Intellij IDEA15来完成日常开发工作,使用JUnit来进行单元测试的工作,对我们所写的代码进行正确性的测试,并为后期的项目维护做好准备,以及提升代码的质量和出错率,Debug的过程一定是痛苦的。

本文中我们所使用的是JUnit4版本,不过目前JUnit5也已经出来了。

环境搭建以及前期准备

  • 首先,在一个新建的项目中,在项目根目录下新建一个测试文件夹,此处为了易于辨识,我们取做“tests”;



  • 然后,“Command+;”进入到项目结构,选择Modules子选项并把tests文件夹添加为测试目录,此时文件夹的颜色由灰色变为蓝色,点击ok确认即可;


  • 最后,我们在src目录下的com.sh2zqp.bean包下新建一个类Person,类里面添加一个name属性和一个getName()和一个setName()方法。

    public class Person {

    private String name;
    public Person(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    }
    

注意

之所以把测试代码和源代码分开是因为一般测试代码是不会公开的,只是我们开发人员自己使用,把它们单独放在tests目录下更易于实现这样的管理。

生成测试类PersonTest

  • 首先把鼠标定位到Person类上,快捷键Alt(option)+Enter(return),选择Create Tests选项;


  • 然后,进入Create Tests设置页面,选择Testing Libary为JUnit4,我们发现里面有不少的测试库可以使用;

  • 但是,我们发现JUnit4库并没有被引入项目Module中,此时我们点击fix,选择第一项;,点击ok;

  • 最后,我们选择Person类中的getName()方法进行测试,点击ok即可,之后我们发现项目的结构如下。


可以发现测试类PersonTest中的有一个getName的测试方法,方法上面有一个@Test注解

编写测试代码

@Test
public void getName() throws Exception {
    Person person = new Person("sh2zqp");
    assertEquals("sh2zqp", person.getName());
}

代码说明

  • 测试方法上面必须使用@Test注解进行修饰;
  • 测试方法必须使用public void 进行修饰,不能带有任何参数;
  • 测试方法必须抛出throws Exception异常;
  • 新建一个源代码目录tests用来存放测试代码;
  • 测试类的包应该与被测试类的包保持一致;
  • 测试单元中的每一个方法必须独立测试,每个测试方法之间不能有依赖;
  • 测试类使用Test做为类名的后缀(非必要);
  • 测试方法使用test作为方法名的前缀(非必要);

运行测试代码



我们也可以把鼠标方法测试类PersonTest或测试方法getName()上,通过快捷键Alt+Enter来完成测试运行。


测试结果如下:

此外,我们通过在页面任意空白处使用Command+N添加新的测试方法,如下:


测试错误示范

我们为setName()方法添加了测试方法

@Test
public void setName() throws Exception {
    Person person = new Person("sh2zqp");
    person.setName("sh2zqp1");
    assertEquals("sh2zqp", person.getName());
}

很明显assertEquals(“sh2zqp”, person.getName())中“sh2zqp”并不是person.getName()所期望的值,因为我们已经通过setName()方法更改为“sh2zqp1”。

另外,setName和getName方法混合使用,说明此处的setName已经不是独立的测试单元。

注意

  • Failure 一般是单元测试使用的断言方法判断失败引起,说明预期结果和程序运行结果不一致;
  • error 是有代码异常引起的,他产生于测试代码本身中的Bug;
  • 测试用例不是用来证明你是对的,而是用来证明你没有错;

JUnit单元测试的深入学习

上一部分我们简单的使用了JUnit进行了单元测试,本部分我们进一步来学习。

JUnit测试流程

在PersonTest测试类中加入如下代码:

@BeforeClass
public static void setUpBeforeClass() throws Exception {
    System.out.println("BeforeClass");
}
@AfterClass
public static void setUpAfterClass() throws Exception {
    System.out.println("AfterClass");
}
@Before
public void setUp() throws Exception {
    System.out.println("Before");
}
@After
public void tearDown() throws Exception {
    System.out.println("After");
}

@Test
public void getName() throws Exception {
    System.out.println("test getName()");
    Person person = new Person("sh2zqp1");
    assertEquals("sh2zqp1", person.getName());
}
@Test
public void setName() throws Exception {
    System.out.println("test setName()");
    Person person = new Person("sh2zqp");
    person.setName("sh2zqp1");
    assertEquals("sh2zqp1", person.getName());
}

这里我们学习四个新的注解@BeforeClass,@AfterClass,@Before,@After,下面对这几个注解做出说明:

  • @BeforeClass:所修饰的方法在所有方法加载前执行,而且他是静态的在类加载后就会执行该方法,在内存中只有一份实例,适合用来加载配置文件;
  • @AfterClass:所修饰的方法在所有方法执行完毕之后执行,通常用来进行资源清理,例如关闭数据库连接;
  • @Before@After在每个测试方法执行前都会执行一次。

JUnit常用注解

  • @Test:将一个普通的方法修饰成为一个测试方法
    • @Test(exception=xxx.class)在运行时忽略某个异常
    • @Test(timeout=毫秒数)允许程序运行的时间

@Test可以附带参数,首先在Person类中新增一个divideByPerson()方法,然后在PersonTest类中新增测试方法,具体如下:

public int divideByPerson(int a, int b) {
        return a/b;
}
    @Test
    public void divideByPerson() throws Exception {
        assertEquals(6, person.divideByPerson(6,0));
    }

测试结果如下:

可以看到ArithmeticException算数错误,报了使用@Test(exception=xxx.class),代码如下:

@Test(expected = ArithmeticException.class)
public void divideByPerson() throws Exception {
    assertEquals(6, person.divideByPerson(6,0));
}

运行结果如下:

@Test另外还有一个参数@Test(timeout=毫秒数),其目的给出一个程序运行的最大时间,时间到了会自动停止,一般用于循环执行的代码块,避免出现死循环。

  • @BeforeClass@AfterClass@Before@After(参见上面的解释)

  • @Ignore:所修饰的方法会被测试器忽略,里面可以附加一些提示信息@Ignore(“……”)

    @Ignore("ignore")
    @Test
    public void getName() throws Exception {
        System.out.println("test getName()");
        assertEquals("sh2zqp", person.getName());
    }
    

  • @RunWith:更改测试运行器,自定义测试器,需要继承org.junit.runner.Runner,大多数情况下使用默认的测试运行器即可。
  • assert断言的使用

静态导入
import static org.junit.Assert

JUnit测试套件的使用

测试套件是组织测试类一起运行的测试类,是随着项目规模的变大的一种简易测试方法,可以批量运行测试类,把这些测试类集中到一个测试套件中即可。

我们新建的一个测试套件类SuiteTest和三个测试类Test1,Test2,Test3,如下:

public class Test1 {
    @Test
    public void test() throws Exception {
        System.out.println("test1......");
    }
}
public class Test2 {
    @Test
    public void test() throws Exception {
        System.out.println("test2......");
    }
}
public class Test3 {
    @Test
    public void test() throws Exception {
        System.out.println("test3......");
    }
}

@RunWith(Suite.class)
@Suite.SuiteClasses({Test1.class, Test2.class, Test3.class})
public class SuiteTest {
}

运行结果

说明

  • 作为测试套件的入口类,类中不能包含任何方法,并用public修饰;
  • 更改测试运行器Suite.class(@RunWith(Suite.class));
  • 将需要运行的测试类放入Suite.SuiteClasses({})的数组中,当然里面也可以放测试套件类。

JUnit参数化设置

需要测试的仅仅是测试数据,代码结构是不变的,只需要更改测试数据。

@RunWith(Parameterized.class)
public class ParameterTest {

    String expected = "";
    String input = "";

    @Parameterized.Parameters
    public static Collection<Object[]> t() {
        return Arrays.asList(new Object[][] {
                {"sh2zqp1","sh2zqp1"},
                {"sh2zqp2","sh2zqp2"}
        });
    }

    public ParameterTest(String expected, String input) {
        this.expected = expected;
        this.input = input;

    }

    @Test
    public void testGetName() throws Exception {
        Person person = new Person(input);
        assertEquals(expected, person.getName());
    }
}

具体步骤

  • 更改默认的测试运行器为@RunWith(Parameterized.class);
  • 声明变量来存放预期值和测试值;
  • 声明一个返回值为Collection的公共静态方法,并用@Parameters修饰;
  • 为测试类声明一个带有参数的公共构造函数,并在其中为他声明变量赋值。

运行结果

JUnit4在Web项目中的使用

后期添加

参考资料

JUnit 4 with IntelliJ: A quick introduction
JUnit单元测试–IntelliJ IDEA
JUnit—Java单元测试必备工具

QinPeng Zhu wechat
扫一扫,关注我的公众号获取更多资讯!
学习分享,感谢鼓励!