В минувшее воскресенье Sam Brannen анонсировал выход JUnit 5! Ура!
Поздравляю всех участников @JUnitTeam а также всех, кто использует JUnit в своей работе! Давайте посмотрим, что же нам приготовили в этом релизе.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage (< офф.сайт).
@Test
void test() {
assertEquals("It " + " works!" == "It works!");
}
assertEquals(2017, 2017, "The optional assertion message is now the last parameter.");
assertTrue("habr" == "habr", () -> "Assertion messages can be lazily evaluated");
// в группе все ассерты исполняются независимо,
// успех - когда прошли успешно все ассерты
assertAll("habr",
() -> assertThat("https://habrahabr.ru", startsWith("https")),
() -> assertThat("https://habrahabr.ru", endsWith(".ru"))
);
assertIterableEquals(asList(1, 2, 3), asList(1, 2, 3));
Assertions.assertLinesMatch(
asList("можно сравнивать строки", "а можно по regex: \\d{2}\\.\\d{2}\\.\\d{4}"),
asList("можно сравнивать строки", "а можно по regex: 12.09.2017")
);
Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("что-то пошло не так");
});
assertEquals("что-то пошло не так", exception.getMessage());
// JUnit 4
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Test {
Class<? extends Throwable> expected() default Test.None.class;
long timeout() default 0L;
public static class None extends Throwable {
private static final long serialVersionUID = 1L;
private None() {
}
}
}
// JUnit 5
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(Stable)
@Testable
public @interface Test {
}
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
class StandardTests {
// вместо @BeforeClass
@BeforeAll
static void initAll() {
}
// вместо @Before
@BeforeEach
void init() {
}
@Test
void succeedingTest() {
}
@Test
void failingTest() {
fail("a failing test");
}
// Вместо @Ignore
@Test
@Disabled("for demonstration purposes")
void skippedTest() {
// not executed
}
// Новая аннотация для улучшения читаемости при выводе результатов тестов.
@DisplayName("?°?°)?")
void testWithDisplayNameContainingSpecialCharacters() {}
// вместо @After
@AfterEach
void tearDown() {
}
// вместо @AfterClass
@AfterAll
static void tearDownAll() {
}
}
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.EmptyStackException;
import java.util.Stack;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@DisplayName("A stack")
class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() {
new Stack<>();
}
@Nested
@DisplayName("when new")
class WhenNew {
@BeforeEach
void createNewStack() {
stack = new Stack<>();
}
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("throws EmptyStackException when popped")
void throwsExceptionWhenPopped() {
assertThrows(EmptyStackException.class, () -> stack.pop());
}
@Test
@DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() {
assertThrows(EmptyStackException.class, () -> stack.peek());
}
@Nested
@DisplayName("after pushing an element")
class AfterPushing {
String anElement = "an element";
@BeforeEach
void pushAnElement() {
stack.push(anElement);
}
@Test
@DisplayName("it is no longer empty")
void isNotEmpty() {
assertFalse(stack.isEmpty());
}
@Test
@DisplayName("returns the element when popped and is empty")
void returnElementWhenPopped() {
assertEquals(anElement, stack.pop());
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("returns the element when peeked but remains not empty")
void returnElementWhenPeeked() {
assertEquals(anElement, stack.peek());
assertFalse(stack.isEmpty());
}
}
}
}
@RepeatedTest(5)
void repeatedTest() {
System.out.println("Этот тест будет запущен пять раз. ");
}
@ParameterizedTest
@ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
assertNotNull(argument);
}
@ParameterizedTest
@ValueSource(strings = { "01.01.2017", "31.12.2017" })
void testWithConverter(@JavaTimeConversionPattern("dd.MM.yyyy") LocalDate date) {
assertEquals(2017, date.getYear());
}
@ParameterizedTest
@CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" })
// или даже так: @CsvFileSource(resources = "/two-column.csv")
void testWithCsvSource(String first, int second) {
assertNotNull(first);
assertNotEquals(0, second);
}
@ParameterizedTest
@EnumSource(value = TimeUnit.class, names = { "DAYS", "HOURS" })
void testWithEnumSourceInclude(TimeUnit timeUnit) {
assertTrue(EnumSet.of(TimeUnit.DAYS, TimeUnit.HOURS).contains(timeUnit));
}
@ParameterizedTest
@ArgumentsSource(MyArgumentsProvider.class)
void testWithArgumentsSource(String argument) {
assertNotNull(argument);
}
static class MyArgumentsProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of("foo", "bar").map(Arguments::of);
}
}
public interface Testable<T> {
T createValue();
}
public interface EqualsContract<T> extends Testable<T> {
T createNotEqualValue();
@Test
default void valueEqualsItself() {
T value = createValue();
assertEquals(value, value);
}
@Test
default void valueDoesNotEqualNull() {
T value = createValue();
assertFalse(value.equals(null));
}
@Test
default void valueDoesNotEqualDifferentValue() {
T value = createValue();
T differentValue = createNotEqualValue();
assertNotEquals(value, differentValue);
assertNotEquals(differentValue, value);
}
}
К сожалению, не доступен сервер mySQL