JUnit is considered the standard unit testing framework to test Java applications. Now days every IDE comes with the inbuilt support of JUnit, For this Junit Mockito Tutorial we will be using JUnit 5 and Eclipse Oxygen version.
There are few changes in Junit 5 compared with junit 4, below are few major changes in JUnit 5
1. Annotations reside in the
2. Assertions reside in
3. Assumptions reside in
4. @Before and @After no longer exist; use @BeforeEach and @AfterEach instead.
5. @BeforeClass and @AfterClass no longer exist; use @BeforeAll and @AfterAll instead.
6. @Ignore no longer exists: use @Disabled instead.
7. @Category no longer exists; use @Tag instead.
8. @RunWith no longer exists; superseded by @ExtendWith.
9. @Rule and @ClassRule no longer exist; superseded by @ExtendWith
JUnit provides may annotations, we have explained them below based on the usage, Neither test classes nor test methods need to be public in Junit 5.
Methods annotated with @Test, @TestTemplate, @RepeatedTest, @BeforeAll, @AfterAll, @BeforeEach, or @AfterEach annotations must not return a value, So always the return type of the method shoud be void.
@Test is the actual test method where we place our code to test the applications.
@BeforeTest method will be executed before executing the @Test method, @AfterTest executes for each and every @Test
@AfterTest method will be executed after @Test method compltes its execution, @AfterTest executes for each and every @Test
@BeforeAll method will be executed before executing any method in the class, @BeforeAll method gets executed once per class
@AfterAll method will be executed after completing execution of all the methods in the class, @BeforeAll method gets executed once per class
@Disabled annotation used to tell the compiler that method should not be executes, @Disabled makes the method to skip.
@DisplayName displays a custom name for the method / class, @DisplayName is applicable for class and methods. Display name can contain alphabets, spaces, special characters, and even emojis
import static org.junit.Assert.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.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("Class level Display name")
public class SampleJunit {
@BeforeAll
static void initAll() {
System.out.println("@BeforeAll");
}
@BeforeEach
void init() {
System.out.println("@BeforeEach");
}
@Test
void succeesTest() {
System.out.println("@Test Success");
}
@Test
@DisplayName("Fail test : Chercher Tech")
void failingTest() {
System.out.println("@Test failure");
fail("Failing the test to to demo");
}
@Test
@Disabled("for demo purposes")
void skippedTest() {
// not executed
fail("Failing the test to to demo");
}
@AfterEach
void tearDown() {
System.out.println("@AfterEach");
}
@AfterAll
static void tearDownAll() {
System.out.println("@AfterAll");
}
}
Output of Junit Annotations :
From the above out itself we can know the order of execution in Junit:
1. BeforeAll
2. BeforeEach
3. Test
4. AfterEach
5. AfterAll
In JUnit 5 all the assertions are present at
fail() method fails the current 2test test case without checking for any conditions, this method will be useful incase where you have to fail a test case when an particular exception occurs.
assertTrue method verifies whether given parameter is true/results in true or not, in case if the parameter is false then assertTrue method fails the testcase. We can also mention the reason for failure.
assertFalse method verifies whether given parameter is false/results in false or not, in case if the parameter is true then assertFalse method fails the testcase. We can also mention the reason for failure.
verifies whether given object is null or not, in case if the object is not null then Junit fails the test case.
verifies whether given object is not null or not, in case if the object is null then Junit fails the test case.
assertEquals method compares whether two give values are same or not, if the values are diffrent then Junit fails the testcase. This method is overloaded to accept all kind of values, from Byte to Object class.
assertArrayEquals method compares two given arrays, fails incase both arrays are different. This method is also overloaded to accept all the values in java.
assertIterableEquals method verifies whether given iterable are same are not, below example shos that same values stored in ArrayList and LinkedList, even though those are two different object, this method verifies whether values are in matching order or not.
assertNotEquals method verifies given two object and fails if both object are same, assertNotEquals method is also overloaded to accept all the values in java.
assertAll method verifies all the assertions passed to this method.
assertThrows method verfies whether given code throws exception or not, Junit fails the testcase incase if no exception occurs.
assertTimeout method asserts that execution of the supplied executable code completes before the given timeout is exceeded.
Even though the assertion facilities provided by JUnit Jupiter are sufficient for many testing scenarios, there are times when more power and additional functionality such as matchers are desired or required.
In such cases, the JUnit team recommends the use of third-party assertion libraries
Till JUnit 4 developers were using assertThat() method present in the
Hamcrest allows checking for conditions in your code using matchers classes present hamcrest API.
int i = 10;
int j = 10;
// all statements test the same
assertThat(i, equalTo(j));
assertThat(i, is(equalTo(j)));
assertThat(i, is(j));
To get the same result as above wwe can use the Junit's assertEquals method.
assertThat("Chercher Tech", containsString("Tech")));
In Junit we can tag a test using @Tag annotation, @Tag helps to identify a test. We can execute and filter the test based on the tages that we provide. Tagging similar to groups in TestNG, for Example if we wat to run only 'smoke' tests we can tag test which we want to execute as part of smoke test.
Test classes and methods can be tagged via the @Tag annotation. @Tag names should follow below conventions.
1. A tag must not be null or blank.
2. A trimmed tag must not contain whitespace. (Trimmed means whitespaces removed at ends)
3. Tag must not contain ISO control characters.
4. Tag must not contains special characters like : ',: comma', '(: left parenthesis', '): right parenthesis', '&: ampersand', '|: vertical bar', '!: exclamation point'
We can execute a single testase multiple times, JUnit 5/Jupiter provides the ability to repeat a test a specified number of times simply by annotating a method with @RepeatedTest
Each invocation of a repeated test behaves like the execution of a regular @Test method
When we are using @RepeatedTest annotations, we can avoid using the @Test annotations. When we use both of the annotations, the number of times the test case will be execute is repeatedTest + 1.
below is the testcase with @RepeatedTest alone
@RepeatedTest(3)
void succeesTest() {
System.out.println("This test will be executed 3 times");
}
Output of Repeated test.
Let's see what happens when we include @Test annotations
@Test
@RepeatedTest(3)
void succeesTest() {
System.out.println("Repeated test along with test");
}
Output of @RepeatedTest along with @Test
@ParameterizedTest annotation allows user to achieve Parameterization, Parameterization is nothing but testing a method / test using multople data. Parameterized tests make it possible to run a test multiple times with different arguments.
In TestNG this is known as dataProvider, JUnit 5 provides much more options to test a method with multiple values
We will be using @ParameterizedTest instead of @Test annotations, along with @ParameterizedTest we also have to provide the source where to get the values
Different data sources :
1. @ValueSource
2. @EnumSource
3. @MethodSource
4. @CsvSource
5. @CsvFileSource
6. @ArgumentsSource
@ValueSource used for reading the data from a String array
@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"})
void testWithSimpleMethodSource(String value) {
System.out.println(value);
}
Output of the @ValueSource
@EnumSource helps the user to read the data from the Enum, this annotation reads all the data from the Enum.
// file 1
public enum WeekDays {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY;
}
// file 2
@ParameterizedTest
@EnumSource(WeekDays.class)
void testWithSimpleEnumSource(WeekDays enus) {
System.out.println(enus);
}
Output of @EnumSource
We can also fetch only few values from the Enum instead of complete values. We have to set the names parameter as the values that we want to retrieve from the Enum.
@ParameterizedTest
@EnumSource(value = WeekDays.class, names = {"MONDAY", "FRIDAY"})
void testWithSimpleFewEnumSource(WeekDays enus) {
System.out.println(enus);
}
Output of @EnumSource with few values.
@MethodSource allows you to refer to one or more factory methods of the test class. Such methods must return a Stream, Iterable, Iterator, or array of arguments.
In addition, such methods must not accept any arguments. By default such methods must be static unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS).
@ParameterizedTest
@MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument) {
System.out.println(argument);
}
static Stream stringProvider() {
return Stream.of("abc", "bcd", "xyz");
}
Output of @MethodSource
If you do not explicitly provide a factory method name via @MethodSource, JUnit Jupiter will search for a factory method that has the same name as the current @ParameterizedTest method by convention.
Note : This method is still in development mode so it will not work, When I was writing this tutorial. below method didnot work.
@ParameterizedTest
@MethodSource
void testWithSimpleMethodSourceHavingNoValue(String argument) {
assertNotNull(argument);
}
static Stream testWithSimpleMethodSourceHavingNoValue() {
return Stream.of("foo", "bar");
}
@CsvSource annotations allows user to read from the Comma seprated values as parameter (not as .csv file), With CSV values we can read more than one parameter and as different data type parameter.
In below example we are reading the String and int value.
@ParameterizedTest
@CsvSource({ "one, 1", "two, 2", "'three, tres', 3" })
void testWithCsvSource(String first, int second) {
System.out.println(first + " ::: "+ second);
}
Output of the @CsvSource
Below table explains what happens when the Junit parses the CSV values.
| Example Input | Resulting Argument List |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
@CsvFileSource lets the user to read the data from the csv file rather than reading from program. Each line from a CSV file results in one invocation of the parameterized test.
@ParameterizedTest
@CsvFileSource(resources = "/h.csv")
void testWithCsvFileSource(String first, int second) {
System.out.println(first+ " :: "+second);
}