JUnit4(一)基础

前言:JUnit4引入了注解(Annotation)机制,通过解析注解就可以为测试提供相应的信息,并抛弃了JUnit3使用命名约束以及反射机制的方法。

建议:

  • 不建议使用IDE集成的JUnit,因为其版本是固定的,相对而言可能一些新特性是不支持的。
  • 测试代码放在与src同级的另外一个源文件夹中,方便测试代码的管理。
  • 测试文件的路径结构应与被测试的源文件相同。
  • 测试文件的命名格式为Test+名称,这样更加直观。
  • JUnit4中初始化函数命名为setUp(),释放资源的函数命名为tearDown()【这是为了与JUnit3兼容】。
  • 为了在JUnit4中像JUnit3中直接使用assert[断言],我们要静态导入Assert类(import static org.junit.Assert.*;

一、基础

1.1 Maven依赖

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

注意:JUnit自4.9之后引入了hamcrest-core依赖,因为其包含JUnit所需要的核心匹配器org.hamcrest.CoreMatchers,如果你想使用org.hamcrest.Matchers就需要引入hamcrest-library依赖。

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-library</artifactId>
    <version>1.3</version>
    <scope>test</scope>
</dependency>

1.2 基础

  • 定义一个测试类的要求是,这个类必须是public 的并且包含了一个无参数的构造函数(如果没有定义其它构造函数,Java会为我们隐式地创建它)。
  • 创建一个测试方法的要求是,这个方法必须使用@Test注解,并且是public的,不带任何参数,并且返回值为void类型。
  • JUnit在调用(执行)每个@Test方法之前,为测试类创建一个新的实例。 这有助于提供测试方法之前的独立性,并且避免在测试代码中产生意外的副作用。因为每个测试方法都运行与一个新的测试类实例上,所以我们就不能在测试方法之间重用各个实例变量值。

1.3 Junit最佳实践

  • 一次只测试一个对象
  • 测试方法选择有意义的名字
  • 在调用assert中解释失败的原因
  • 一个单元测试等于一个@Test方法
  • 测试任何可能失败的事务
  • 让测试改善代码
  • 使异常测试更易于阅读
  • 相同的包,分离的目录

二、注解摘要

  • 基本注解
    • @Test:测试代码。
    • @Ignore:忽略的测试方法。
    • @Before:在每个测试之前运行的代码。[标记注解]
    • @After:在每个测试之后运行的代码。[标记注解]
    • @BeforeClass:针对所有测试,只执行一次,且必须为static void。[标记注解]
    • @AfterClass:针对所有测试,只执行一次,且必须为static void。[标记注解]
  • 高级注解
    • @Rule:允许灵活添加或重新定义测试类中的每个测试方法的行为。[Since:4.7]
    • @ClassRule[Since:4.9]
    • @FixMethodOrder:指定测试方法的执行顺序。[Since:4.11] [单值注解]
    • @RunWith:指定测试类使用某个运行器。[完整注解]
      • @Suite.SuiteClasses@SuiteClasses:指定Suite运行器时,用来指定其中包含的测试类。
      • @Parameters:指定测试类的测试数据集合,采用构造方法进行注入。
      • @Parameter:用来取代上面构造方法指定方式,指定注入的字段的索引。
      • @Category:将测试类或测试方法标记为属于一个或多个测试类别。值是任意类的数组。此注解仅由Categories运行器解释。
      • @Categories.IncludeCategory:可简化为 @IncludeCategory
      • @Categories.ExcludeCategory:可简化为 @ExcludeCategory

一个测试类单元测试的执行顺序为:

@BeforeClass → @Before → @Test → @After → @AfterClass

每一个测试方法的调用顺序为:

@Before → @Test → @After

@Test

用于指定该方法为测试用例,通常直接用来标记方法即可,其包含两个可选参数:

  • expected:指定测试应当抛出的异常类型
  • timeout:指定测试超时时间【单位是毫秒】

警告:虽然超时timeout对于捕获和终止无限循环很有用,但不应视为确定性。下面的测试可能会失败,也可能不会失败,这取决于操作系统如何调度线程。

@Test(timeout=100) 
public void sleep100() {
     Thread.sleep(100);
}

线程安全警告:带有timeout参数的测试方法运行时所处的线程与运行的@Before@After方法所处的线程是不同的。与没有timeout参数的相同测试方法进行比较时,对于不是线程安全的代码,这可能会产生不同的行为。可以考虑使用Timeout规则进行替代,其可以确保测试方法与@Before@After方法在运行时处于相同线程中。

@Ignore

如果出于某种原因,您不希望测试失败,您只希望它被忽略,您暂时禁用一个测试。

注意:@Ignore 包含一个可选参数,如果您想记录一个测试被忽略的原因,可以指定其值。

示例:

@Ignore("Test is ignored as a demonstration")
@Test
public void testSame() {
    assertThat(1, is(1));
}

三、测试执行顺序@FixMethodOrder

JUnit在设计上没有指定测试方法的执行顺序,到目前为止,这些方法只是按照反射API返回的顺序调用的,JUnit自4.11版本之后引入了@FixMethodOrder注解,这样就可以指定其运行顺序了。

@FixMethodOrder注解是在类上进行注释的,并提供了三种顺序:

  • @FixMethodOrder(MethodSorters.DEFAULT):默认的顺序,以确定但不可预期的顺序执行。
  • @FixMethodOrder(MethodSorters.JVM):按照JVM得到的方法顺序,也就是代码中定义的方法顺序 。
  • @FixMethodOrder(MethodSorters.NAME_ASCENDING):按方法名字母顺序执行 。
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestMethodOrder {

    @Test
    public void testA() {
        System.out.println("first");
    }
    @Test
    public void testB() {
        System.out.println("second");
    }
    @Test
    public void testC() {
        System.out.println("third");
    }
}

四、Test fixtures

测试fixture是一组对象的固定状态,用作运行测试的基线。测试fixture的目的是确保有一个众所周知的、固定的环境来运行测试,以便结果是可重复的。fixture实例:

  • Preparation of input data and setup/creation of fake or mock objects
  • Loading a database with a specific, known set of data
  • Copying a specific known set of files creating a test fixture will create a set of objects initialized to certain states.

JUnit提供了注解,这样测试类就可以在每次测试之前或之后运行fixture,或者只在类的所有测试方法之前和之后运行一次。

JUnit包含四个fixture注解:两个用于类级的fixture,两个用于方法级的。

  • 类级别的:@BeforeClass@AfterClass
  • 方法级别的:@Before@After

@BeforeClass@AfterClass在类的所有方法执行前以及执行后分别执行。而@Before@After在类的每个方法前后都会执行。

五、断言

JUnit提供了所有原始类型、对象和数组的重载断言方法。参数顺序是期望值,后面是实际值。[可选地] 第一个参数可以是在失败时输出的字符串消息。

注意:有一个稍微不同的断言是 assertThat , 第一个是可选参数用来在失败时进行输出,接下来是实际值,最后是一个Matcher对象。需要注意的是期望值和实际值与其他断言是相反的。

常用方法 解释
assertArrayEquals(expecteds, actuals) 查看两个数组是否相等
assertEquals(expected, actual) 查看两个对象是否相等,类似于字符串比较使用的equals()方法
assertNotEquals(first, second) 查看两个对象是否不相等。
assertNull(object) 查看对象是否为空
assertNotNull(object) 查看对象是否不为空
assertSame(expected, actual) 查看两个对象的引用是否相等。类似于使用“==”比较两个对象
assertNotSame(unexpected, actual) 查看两个对象的引用是否不相等。类似于使用“!=”比较两个对象
assertTrue(condition) 查看运行结果是否为true
assertFalse(condition) 查看运行结果是否为false
assertThat(actual, matcher) 查看实际值是否满足指定的条件
fail() 让测试失败

示例:

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.hamcrest.core.CombinableMatcher;
import org.junit.Test;

public class AssertTests {
  @Test
  public void testAssertArrayEquals() {
    byte[] expected = "trial".getBytes();
    byte[] actual = "trial".getBytes();
    assertArrayEquals("failure - byte arrays not same", expected, actual);
  }

  @Test
  public void testAssertEquals() {
    assertEquals("failure - strings are not equal", "text", "text");
  }

  @Test
  public void testAssertFalse() {
    assertFalse("failure - should be false", false);
  }

  @Test
  public void testAssertNotNull() {
    assertNotNull("should not be null", new Object());
  }

  @Test
  public void testAssertNotSame() {
    assertNotSame("should not be same Object", new Object(), new Object());
  }

  @Test
  public void testAssertNull() {
    assertNull("should be null", null);
  }

  @Test
  public void testAssertSame() {
    Integer aNumber = Integer.valueOf(768);
    assertSame("should be same", aNumber, aNumber);
  }

  // JUnit Matchers assertThat
  @Test
  public void testAssertThatBothContainsString() {
    assertThat("albumen", both(containsString("a")).and(containsString("b")));
  }

  @Test
  public void testAssertThatHasItems() {
    assertThat(Arrays.asList("one", "two", "three"), hasItems("one", "three"));
  }

  @Test
  public void testAssertThatEveryItemContainsString() {
    assertThat(Arrays.asList(new String[] { "fun", "ban", "net" }), everyItem(containsString("n")));
  }

  // Core Hamcrest Matchers with assertThat
  @Test
  public void testAssertThatHamcrestCoreMatchers() {
    assertThat("good", allOf(equalTo("good"), startsWith("good")));
    assertThat("good", not(allOf(equalTo("bad"), equalTo("good"))));
    assertThat("good", anyOf(equalTo("bad"), equalTo("good")));
    assertThat(7, not(CombinableMatcher.<Integer> either(equalTo(3)).or(equalTo(4))));
    assertThat(new Object(), not(sameInstance(new Object())));
  }

  @Test
  public void testAssertTrue() {
    assertTrue("failure - should be true", true);
  }
}

六、junit3和junit4的使用区别:

  1. 在JUnit3中需要继承TestCase类,但在JUnit4中已经不需要继承TestCase
  2. 在JUnit3中需要覆盖TestCase中的setUptearDown方法,其中setUp方法会在测试执行前被调用以完成初始化工作,而tearDown方法则在结束测试结果时被调用,用于释放测试使用中的资源,而在JUnit4中,只需要在方法前加上@Before@After注解
  3. 在JUnit3中对某个方法进行测试时,测试方法的命令是固定的,例如对addBook这个方法进行测试,需要编写名字为testAddBook的测试方法,而在JUnit4中没有方法命令的约束,在方法的前面加上@Test,这就代表这个方法是测试用例中的测试方法
  4. 新的断言assertThat
  5. @BeforeClass 和 @AfterClass 。在JUnit3,如果所有的test case仅调用一次setUp()和tearDown()需要使用TestSetup类
  6. 测试异常处理@Test(expected = DataFormatException.class)
  7. 设置超时@Test(timeout = 1000)
  8. 忽略测试@Ignore
  9. 集成测试

赞赏码

猜你喜欢

转载自blog.csdn.net/fanxiaobin577328725/article/details/78407131