导航

  • 我们为什么需要单元测试框架?
  • 为工程添加JUnit支持
  • 编写JUnit单元测试案例
    • JUnit常用注解
    • JUnit常用断言
    • JUnit案例
    • Spring整合

我们为什么需要单元测试框架?

  当我们需要对一段代码进行测试时,怎么样让他快速跑起来呢?一个很自然的想法是编写一个main()方法,然后运行一些测试代码,我想各位大多都用过这种方法。

  但是使用main()方法测试有很多缺点:一个类只能有一个main()方法,难以同时编写多个测试案例;没有详细的测试结果,如期望值、实际值等,若想实现,则需要自行开发的代码量过多;如果需要用到Spring容器等,则简单的main()方法实现起来也不再简单。

  因此,我们需要一种测试框架,帮助我们编写单元测试案例。

为工程添加JUnit支持

  JUnit是一个开源的Java语言的单元测试框架,专门针对Java设计,使用最广泛。JUnit是事实上的单元测试的标准框架,任何Java开发者都应当学习并使用JUnit编写单元测试。

  使用JUnit编写单元测试的好处在于,我们可以非常简单地组织测试代码,并随时运行它们,JUnit就会给出成功的测试和失败的测试,还可以生成测试报告,不仅包含测试的成功率,还可以统计测试的代码覆盖率,即被测试的代码本身有多少经过了测试。对于高质量的代码来说,测试覆盖率应该在60%以上,但也不用过分追求覆盖率,需要考虑边际效益的影响。

  几乎所有的IDE工具都集成了JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试。

  以IDEA为例,首先我们需要增加JUnit的依赖,如果为maven工程,则直接在pom文件里加上如下依赖即可,如果是普通工程,则需要自行下载jar包并导入。

		<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

  然后打开需要被测试的类,右键 -> Generate,然后选择JUnit版本

  或者右键 -> Go To -> Test,若这个类还未创建测试类,则会提示创建。

  IDEA会自动在test包下,生成对应目录与测试文件。

  需要注意的是test目录需被设置为Tests source root,若未自动设置,需在右上角File->Project Structure->Modules下,进行设置。

编写JUnit单元测试案例

JUnit常用注解

  JUnit中的常用注解如下:

注解作用
@BeforeClass表示在类刚开始时执行,只会执行一次
@AfterClass表示在类结束时执行,只会执行一次
@Before表示在每个被@Test注解的方法之前执行
@After表示在每个被@Test注解的方法之后执行
@Test用于标注测试方法,一个类里可以有多个

  当一个测试类跑起来时,执行顺序为:

@BeforeClass -> @Before -> @Test -> @After -> @AfterClass

JUnit常用断言

  JUnit中的常用断言如下:

断言方法解释
assertEquals(expected,actual)对比两个对象是否相等
assertNotEquals(unexpected, actual)对比两个对象是否不相等
assertSame(expected, actual)对比两个对象是否为同一个对象
assertNotSame(unexpected, actual)对比两个对象是否为不同对象
assertNull(object)查看对象是否为空
assertNotNull(object)查看对象是否不为空
assertTrue(condition)判断表达式是否为true
assertFalse(condition)判断表达式是否为false
assertFalse(condition)判断表达式是否为false
assertArrayEquals(expecteds, actuals)对比两个数组是否相等
fail()直接断言为失败

JUnit案例

  来一个demo~新建一个Factorial类,提供一个计算阶乘的静态方法:

public class Factorial {
    public static long calculationFactorial(long n) {
        if (n < 0) {
            throw new IllegalArgumentException();
        }
        long r = 1;
        for (long i = 1; i <= n; i++) {
            r = r * i;
        }
        return r;
    }
}

  编写这个类的测试类:


public class FactorialTest {

    @BeforeClass
    public static void beforeClass(){
        System.out.println("我先“执行”为敬! -- -- by @BeforeClass");
    }
    @AfterClass
    public static void afterClass(){
        System.out.println("测试案例都跑完了,该我执行了 -- by @AfterClass");
    }

    @Before
    public void before(){
        System.out.println("我在每个案例前先执行 -- by @Before");
    }

    @After
    public void after(){
        System.out.println("我在每个案例后执行 -- by @After");
    }

    @Test
    public void given_5_when_calculation_then_get_120() {
        System.out.println("案例:输入5 期望120,执行中");
        long result = Factorial.calculationFactorial(5);
        assertEquals(120,result);
    }

    @Test
    public void given_1_when_calculation_then_get_1() {
        System.out.println("案例:输入1 期望1,执行中");
        long result = Factorial.calculationFactorial(1);
        assertEquals(1,result);
    }

    @Test
    public void given_0_when_calculation_then_get_1() {
        System.out.println("案例:输入0 期望1,执行中");
        long result = Factorial.calculationFactorial(0);
        assertEquals(1,result);
    }

    @Test
    public void given_negative_when_calculation_then_exception() {
        System.out.println("案例:输入负数 期望IllegalArgumentException异常,执行中");
        try{
            Factorial.calculationFactorial(-1);
            fail();
        }catch (Exception e){
            assertEquals(IllegalArgumentException.class,e.getClass());
        }
    }
}

  执行后,可以在Run标签下查看测试结果报告:

  我Demo里写的Before、Atfer等无具体意义,仅演示用法。在实际工作中,经常会使用这写方法做测试数据的准备与清理。

Spring整合

  如果是对Spring容器做测试,需要从容器中取对象,则还需设法获取Spring容器。

  方案一:可以在每个测试案例里手动获取:

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService",IAccountService.class);

  方案二:使用@Runwith注解。需先导入Spring-test包

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

  再使用@ContextConfiguration指定配置文件。然后就可以在测试类里使用@Autowired从容器里获取对象了:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class FactorialTest {
	@@Autowired
	private Factorial factorial;
}

  方案三:如果使用的是SpringBoot框架,那么直接使用@SpringBootTest注解即可:

@RunWith(SpringRunner.class)
@SpringBootTest
public class BaseTest {
}

更多推荐

Java单元测试框架 - JUnit