4. JUnit 5
• JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
• Current version = 5.3.2
• No public modifier needed
• Require Java 8 or higher
• Support in IntelliJ IDEA and Eclipse IDE
8. @DisplayName("FactMap operation test")
class FactMapTest {
@Nested
@DisplayName("When same key")
inner class MutableFactMap {
@Test
@DisplayName("When insert duplicated key, update old value")
fun `put same item`() {
val o1 = facts.put("foo", 1)
val o2 = facts.put("foo", 2)
assertNull(o1)
assertEquals(1, o2)
}
}
@Test
fun `facts must have unique name`() {
// …
}
}
11. Assertions
@Test
fun `put same item`() {
val o1 = facts.put("foo", 1)
val o2 = facts.put("foo", 2)
assertNull(o1) { "o1 should be null" }
assertEquals(1, o2) { "o2 should be 1" }
}
12. Assertions
assertAll(
Executable { assertNull(o1) { "o1 should be null" } },
Executable { assertEquals(1, o2) { "o2 should be 1" } }
)
assertThrows(IllegalArgumentException::class.java) {
facts.put("", 1)
}
assertTimeout(Duration.ofMillis(200)) {
Thread.sleep(150)
}
assertTimeoutPreemptively(Duration.ofMillis(200)) {
Thread.sleep(150)
}
13. Assumptions
If assumption fails -> test is skipped
@Test
fun `already exists`() {
// facts is empty -> assumeFalse is failed -> skip assertEquals
assumeFalse { facts.isEmpty() }
// Skip tests
assertEquals(2, 1)
}
14. Dynamic Tests
@TestFactory
fun testRules(): Stream<DynamicTest> {
return IntStream.range(1, 3)
.mapToObj { it ->
dynamicTest("test for input=$it") {
assertEquals(it * 2, it + it)
}
}
}
https://www.baeldung.com/junit5-dynamic-tests
15. Conditional Test Execution
• ExecutionCondition as Extension API
• DisabledCondition is simplest example with
@Disabled annotation
16. Conditional Test Execution
• @EnabledOnOS(…)
• @EnabledOnJre(…)
• @EnabledIfSystemProperty(named=“”, matches=“”)
• @EnabledIfEnvironmentalVariable(named=“”,
matches=“”)
• @EnabledIf(“”) - Support for script, EXPERIMENTAL
17. Parameterized Tests
• Experimental feature
• Need “junit-jupiter-params”
• Resources
• JUnit 5 Parameterized Tests: Using Different Input
• JUnit 5 Parameterized Tests
23. Parallel Test Execution
• Synchronization for shared resources
• @Execution(CONCURRENT)
• @Execution(SAME_THREAD)
• ResourceLock(value=…, mode=…)
• Value
custom|SYSTEM_PROPERTIES|SYSTEM_OUT|SYSTEM_ERR
• Mode
READ | READ_WRITE
• JUnit 5 Synchronization
24. What else?
• @Tag and filtering in build script
• @RepeatedTest with dynamic placeholder for
@DisplayName
• @TestTemplate/
TestTemplateInvocationContextProvider
• Extension API, extensions registered via @ExtendWith
• Custom Extensions in kotlinx-junit-jupiter
26. Introduction
• Java library to launch Docker containers during Tests
• Integration tests against the data access layer
• Integration tests with external dependencies
e.g. message broker, database, cache …
• UI Tests with containerized, Selenium compatible,
Web browsers
27. Introduction
• Current version : 1.10.3
• Requires Docker installation
• Requires Java 8 or higher
• Compatible with JUnit 4 / 5
28. Usecases
• Data access layer integration tests: use a containerized instance of a
MySQL, PostgreSQL or Oracle database to test your data access layer code for
complete compatibility, but without requiring complex setup on developers'
machines and safe in the knowledge that your tests will always start with a
known DB state.Any other database type that can be containerized can also be
used.
• Application integration tests: for running your application in a short-lived
test mode with dependencies, such as databases, message queues or web servers.
• UI/Acceptance tests: use containerized web browsers, compatible with
Selenium, for conducting automated UI tests. Each test can get a fresh instance of
the browser, with no browser state, plugin variations or automated browser
upgrades to worry about.And you get a video recording of each test session, or
just each session where tests failed.
29. JUnit 4
@ClassRule
public static GenericContainer mysql =
new MySQLContainer().withExposedPorts(3306);
@Test
public void getExposedPorts() {
List<Integer> ports = mysql.getExposedPorts();
assertThat(ports).contains(3306);
}
32. Generic Container
• Offers flexible support for any container image as test
dependency
• Reference public docker images
• Internal dockerized services
34. Generic Container - Kotlin
object RedisContainer : KLogging() {
// For Kotlin language spec
class KGenericContainer(imageName: String) : GenericContainer<KGenericContainer>(imageName)
val instance by lazy { startRedisContainer() }
private fun startRedisContainer() = KGenericContainer("redis:4.0.11").apply {
withExposedPorts(6379)
setWaitStrategy(HostPortWaitStrategy())
withLogConsumer(Slf4jLogConsumer(log))
start()
}
val host: String by lazy { instance.containerIpAddress }
val port: Int by lazy { instance.getMappedPort(6379) }
val url: String by lazy { "redis://$host:$port" }
}
35. Specialized Container
• Create images from Dockerfile
• withFileFromString(…)
• withFileFromClasspath(…)
• Use Dockerfile DSL to define Dockerfiles in code
36. Specialized Container
• Use database container to test database specific
features
• No local setup or VM
• 100% database compatibility instead of H2
• MySQL
• PostgreSQL
• Oracle XE
38. Alternatives
• TestNG
• Other JVM languages
• Groovy, Spock, Testcontainers-Spock
• Kotlin, Testcontainers (with workaround)
39. Resources
• JUnit 5
• JUnit 5 Basic
• JUnit 5 : Next step in automated testing
• How to perform a productivee testing using JUnit 5 on Kotlin
• Test Containers
• Test containers Official site
• Docker Test Containers in Java Test
• TestContainers and Spring Boot
• Don’t use In-Memory Database (H2, Congo) for Tests