diff --git a/README.md b/README.md
index cd4ca9be..338d5635 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,8 @@ Jetty | Jetty Server.
JGit | Basic usages of [JGit][jgit].
JMH | Java Microbenchmark Harness (JMH).
JSON | JSON conversion libraries in Java.
-JUnit | JUnit testing framework.
+JUnit 4 | JUnit 4 testing framework.
+JUnit 5 | JUnit 5 testing framework.
Logback | [Logback](http://logback.qos.ch/) logging framework.
Maven | Basic functionality of Maven.
Mongo | The MongoDB database
diff --git a/junit5/pom.xml b/junit5/pom.xml
new file mode 100644
index 00000000..3bcda980
--- /dev/null
+++ b/junit5/pom.xml
@@ -0,0 +1,37 @@
+
+
+
+ java-examples-parent
+ io.mincong
+ 1.0.0-SNAPSHOT
+
+ 4.0.0
+
+ java-examples-junit5
+ Java Examples - JUnit 5
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
\ No newline at end of file
diff --git a/junit5/src/main/java/io/mincong/junit5/ChatBot.java b/junit5/src/main/java/io/mincong/junit5/ChatBot.java
new file mode 100644
index 00000000..ac958669
--- /dev/null
+++ b/junit5/src/main/java/io/mincong/junit5/ChatBot.java
@@ -0,0 +1,5 @@
+package io.mincong.junit5;
+
+public interface ChatBot {
+ String sayHello(String username);
+}
diff --git a/junit5/src/main/java/io/mincong/junit5/StringConcatenationChatBot.java b/junit5/src/main/java/io/mincong/junit5/StringConcatenationChatBot.java
new file mode 100644
index 00000000..bfee123c
--- /dev/null
+++ b/junit5/src/main/java/io/mincong/junit5/StringConcatenationChatBot.java
@@ -0,0 +1,19 @@
+package io.mincong.junit5;
+
+public class StringConcatenationChatBot implements ChatBot {
+
+ @Override
+ public String sayHello(String username) {
+ return "Hello, " + username;
+ }
+
+ /**
+ * In IntelliJ IDEA, run ChatBotTest with coverage and observe the test coverage here. You can see
+ * that this test is not tested. One advantage of using parameterized testing is that it can
+ * increase the test coverage easily with difference scenarios.
+ */
+ @SuppressWarnings("unused")
+ public String sayNo(String username) {
+ return "No, " + username;
+ }
+}
diff --git a/junit5/src/main/java/io/mincong/junit5/StringFormatChatBot.java b/junit5/src/main/java/io/mincong/junit5/StringFormatChatBot.java
new file mode 100644
index 00000000..91c25e68
--- /dev/null
+++ b/junit5/src/main/java/io/mincong/junit5/StringFormatChatBot.java
@@ -0,0 +1,8 @@
+package io.mincong.junit5;
+
+public class StringFormatChatBot implements ChatBot {
+ @Override
+ public String sayHello(String username) {
+ return String.format("Hello, %s", username);
+ }
+}
diff --git a/junit5/src/test/java/io/mincong/junit5/ChatBotTest.java b/junit5/src/test/java/io/mincong/junit5/ChatBotTest.java
new file mode 100644
index 00000000..20d40d15
--- /dev/null
+++ b/junit5/src/test/java/io/mincong/junit5/ChatBotTest.java
@@ -0,0 +1,39 @@
+package io.mincong.junit5;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.ArgumentsProvider;
+import org.junit.jupiter.params.provider.ArgumentsSource;
+
+class ChatBotTest {
+ /**
+ * Use annotation {@link ParameterizedTest} to test multiple implementation of {@link ChatBot}. It
+ * ensures that all implementations respect the specification of the interface and returns the
+ * expected results regardless the internal implementation.
+ *
+ * @param bot the chat bot to test
+ */
+ @ParameterizedTest
+ @ArgumentsSource(ChatBotProvider.class)
+ void sayHello(ChatBot bot) {
+ assertThat(bot.sayHello("Foo")).isEqualTo("Hello, Foo");
+ assertThat(bot.sayHello("Bar")).isEqualTo("Hello, Bar");
+ }
+
+ public static class ChatBotProvider implements ArgumentsProvider {
+
+ /**
+ * This method creates multiple chat bot instances using different implementations and returns
+ * them as a stream of arguments for the parameterized test.
+ */
+ @Override
+ public Stream extends Arguments> provideArguments(ExtensionContext context) {
+ return Stream.of(new StringFormatChatBot(), new StringConcatenationChatBot())
+ .map(Arguments::of);
+ }
+ }
+}
diff --git a/junit5/src/test/java/io/mincong/junit5/MathTest.java b/junit5/src/test/java/io/mincong/junit5/MathTest.java
new file mode 100644
index 00000000..0d3e2582
--- /dev/null
+++ b/junit5/src/test/java/io/mincong/junit5/MathTest.java
@@ -0,0 +1,18 @@
+package io.mincong.junit5;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class MathTest {
+ @ParameterizedTest
+ @CsvSource({
+ "1, 2, 2",
+ "1, -1, 1",
+ "1, 1, 1",
+ })
+ void testMax(int a, int b, int max) {
+ assertThat(Math.max(a, b)).isEqualTo(max);
+ }
+}
diff --git a/pom.xml b/pom.xml
index 9dba8671..c52cdf1c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,7 @@
jetty
protobuf
reliability
+ junit5