断言

JUnit Jupiter提供了许多JUnit4已有的断言方法,并增加了一些适合与Java 8 lambda一起使用的断言方法。所有JUnit Jupiter断言都是org.junit.jupiter.Assertions类中的静态方法。

  1. import static java.time.Duration.ofMillis;
  2. import static java.time.Duration.ofMinutes;
  3. import static org.junit.jupiter.api.Assertions.assertAll;
  4. import static org.junit.jupiter.api.Assertions.assertEquals;
  5. import static org.junit.jupiter.api.Assertions.assertNotNull;
  6. import static org.junit.jupiter.api.Assertions.assertThrows;
  7. import static org.junit.jupiter.api.Assertions.assertTimeout;
  8. import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
  9. import static org.junit.jupiter.api.Assertions.assertTrue;
  10. import org.junit.jupiter.api.Test;
  11. class AssertionsDemo {
  12. @Test
  13. void standardAssertions() {
  14. assertEquals(2, 2);
  15. assertEquals(4, 4, "The optional assertion message is now the last parameter.");
  16. assertTrue(2 == 2, () -> "Assertion messages can be lazily evaluated -- "
  17. + "to avoid constructing complex messages unnecessarily.");
  18. }
  19. @Test
  20. void groupedAssertions() {
  21. // In a grouped assertion all assertions are executed, and any
  22. // failures will be reported together.
  23. assertAll("person",
  24. () -> assertEquals("John", person.getFirstName()),
  25. () -> assertEquals("Doe", person.getLastName())
  26. );
  27. }
  28. @Test
  29. void dependentAssertions() {
  30. // Within a code block, if an assertion fails the
  31. // subsequent code in the same block will be skipped.
  32. assertAll("properties",
  33. () -> {
  34. String firstName = person.getFirstName();
  35. assertNotNull(firstName);
  36. // Executed only if the previous assertion is valid.
  37. assertAll("first name",
  38. () -> assertTrue(firstName.startsWith("J")),
  39. () -> assertTrue(firstName.endsWith("n"))
  40. );
  41. },
  42. () -> {
  43. // Grouped assertion, so processed independently
  44. // of results of first name assertions.
  45. String lastName = person.getLastName();
  46. assertNotNull(lastName);
  47. // Executed only if the previous assertion is valid.
  48. assertAll("last name",
  49. () -> assertTrue(lastName.startsWith("D")),
  50. () -> assertTrue(lastName.endsWith("e"))
  51. );
  52. }
  53. );
  54. }
  55. @Test
  56. void exceptionTesting() {
  57. Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
  58. throw new IllegalArgumentException("a message");
  59. });
  60. assertEquals("a message", exception.getMessage());
  61. }
  62. @Test
  63. void timeoutNotExceeded() {
  64. // The following assertion succeeds.
  65. assertTimeout(ofMinutes(2), () -> {
  66. // Perform task that takes less than 2 minutes.
  67. });
  68. }
  69. @Test
  70. void timeoutNotExceededWithResult() {
  71. // The following assertion succeeds, and returns the supplied object.
  72. String actualResult = assertTimeout(ofMinutes(2), () -> {
  73. return "a result";
  74. });
  75. assertEquals("a result", actualResult);
  76. }
  77. @Test
  78. void timeoutNotExceededWithMethod() {
  79. // The following assertion invokes a method reference and returns an object.
  80. String actualGreeting = assertTimeout(ofMinutes(2), AssertionsDemo::greeting);
  81. assertEquals("hello world!", actualGreeting);
  82. }
  83. @Test
  84. void timeoutExceeded() {
  85. // The following assertion fails with an error message similar to:
  86. // execution exceeded timeout of 10 ms by 91 ms
  87. assertTimeout(ofMillis(10), () -> {
  88. // Simulate task that takes more than 10 ms.
  89. Thread.sleep(100);
  90. });
  91. }
  92. @Test
  93. void timeoutExceededWithPreemptiveTermination() {
  94. // The following assertion fails with an error message similar to:
  95. // execution timed out after 10 ms
  96. assertTimeoutPreemptively(ofMillis(10), () -> {
  97. // Simulate task that takes more than 10 ms.
  98. Thread.sleep(100);
  99. });
  100. }
  101. private static String greeting() {
  102. return "hello world!";
  103. }
  104. }

第三方断言类库

虽然JUnit Jupiter提供的断言功能足以满足许多测试场景的需要,但是有时需要更强大和附加功能,例如匹配器。在这种情况下,JUnit小组推荐使用AssertJHamcrestTruth等第三方断言库。开发人员可以自由使用他们选择的断言库。

例如,匹配器和fluent API的组合可以用来使断言更具描述性和可读性。但是,JUnit Jupiter的org.junit.jupiter.Assertions类没有提供类似于JUnit 4的org.junit.Assert类的assertThat()方法,以接受Hamcrest Matcher。相反,鼓励开发人员使用由第三方断言库提供的匹配器的内置支持。

以下示例演示如何在JUnit Jupiter测试中使用来自Hamcrest的assertThat()支持。 只要Hamcrest库已经添加到classpath中,就可以静态地导入诸如assertThat()is()equalTo()之类的方法,然后像下面的assertWithHamcrestMatcher()方法那样在测试中使用它们。

  1. import static org.hamcrest.CoreMatchers.equalTo;
  2. import static org.hamcrest.CoreMatchers.is;
  3. import static org.hamcrest.MatcherAssert.assertThat;
  4. import org.junit.jupiter.api.Test;
  5. class HamcrestAssertionDemo {
  6. @Test
  7. void assertWithHamcrestMatcher() {
  8. assertThat(2 + 1, is(equalTo(3)));
  9. }
  10. }

当然,基于JUnit 4编程模型的遗留测试可以继续使用org.junit.Assert#assertThat