How To Write JUnit Test Cases (+ Examples)
Table of Contents
- About Junit
- Why Junit?
- How to write the first Junit test?
- How to execute the first Junit test?
- How to write Junit Test Cases?
- What are the most common widely used Junit5 Annotations?
- What are the most common Assertions in Junit 5?
- How can LambdaTest be used to run JUnit Scripts with Selenium?
- How can LambdaTest be used to run JUnit Scripts for parallel test runs?
About Junit
Junit is an open source testing framework to help Java & Kotlin professionals to write and execute different varieties of tests in different levels of Software Testing phases, such as unit testing, integration testing, system testing and acceptance testing in STLC.
There are different versions of Junit. However, we shall explore features of Junit 5 in this article.
Why Junit?
Every experienced developer and an automation test professional would have used Junit at least once in their life, because of its popularity, simplicity, ease of use, flexibility and effectiveness in running tests accurately and elegantly.
With addition of new features in latest versions of Junit, the usage of it looks more attractive in several test frameworks in the software development & testing world.
How to write the first Junit test?
Junit is popularly used in combination with Selenium Web Driver, while writing UI tests for the automation of web & mobile apps testing.
Let us use Eclipse IDE to start writing our first Junit test in Java:
Create a new Java project in Eclipse by navigating to Eclipse Menu:
- Go to ‘File’ menu -> Click on ‘New’ -> Select “Java Project” as guided in the image below
2. Provide a Project name such as “DemoProject” -> Choose a JRE environment such as “JavaSE-14” / choose the most latest available JavaSE version -> Click on “Finish” button in the bottom of the displayed pop-up window
3. If the below module-info window is displayed, select “Don’t create” button
4. When a new Java project is successfully created, right click on the ‘src’ folder and select the following options: New -> Junit Test Case
5. Enter a required package name in ‘Package’ field, and Junit Test Class name in ‘Name’ field
Uncheck all the method stubs as shown below and then click on ‘Finish’ button
(unchecking is optional, if you wish to keep them checked, it’s good too.
6. The newly generated structure of Junit test class is generated now and shall look as similar to the snapshot attached below:
We can also observe that the newly created Junit test class is now under the previous defined package in the navigation pane on the left hand side of Eclipse
7. Now, let us modify the test a bit for a demo run and modify the generated line 11 with System.out.println(“Testing…”);
8. Once the above change is done in line 11, let us prepare ourselves to execute our first Junit test.
How to execute the first Junit test?
- Run the Junit test class by right-clicking on the test class in the navigation pane and selecting Run As option and then choosing the Junit Test option.
Example:
Our first test case:
package jUnit5;import org.junit.jupiter.api.Test;class DemoTest { @Test void test1() { System.out.print("Testing..."); }}
2. After following the above step religiously, now we should be able to see that the selected test is executed successfully and the test result is displayed in the Junit tab with green status denoting that the test has passed successfully.
How to write Junit Test Cases?
- Let us add 2 more tests and see how the Junit test runner works for multiple tests
Note that each test method is written after @Test annotations, denoted in Grey colour in the test class, as in the screenshot below
Example:
Let us try running the below sample test code now and observe the test result:
package jUnit5;import static org.junit.Assert.assertEquals;import org.junit.jupiter.api.Test;class DemoTest { @Test void test1() { System.out.print(“Testing…”); } @Test void test2() { assertEquals(5, 3+2); } @Test void test3() { assertEquals(“Hello”, “hola”); }}
In theory, note that in the above test2() test method, a valid assertion method is passed, where the test is verifying that the expected numeric test data — ‘3+2’ is equal to 5 in actual result post execution or not.
Also, note that in the test3() test method, an incorrect assertion check is passed, to purposefully fail the test post execution, as the expected string “Hello” is not equal to actual result “hola”.
2. Let us run the test again and observe the executed test result
As expected, test2() has passed and test3() has failed.
3. Let us analyse the failed test case by looking at the Failure Trace tab, which is available just below the above displayed test result in Eclipse
Let us understand the failure trace in detail by either clicking on the blue-highlighted line as arrow-marked in the image above or the pointed icon as marked using the second arrow to compare between the actual and expected test result.
With the display of the difference in the expected and actual result as observed in the Result comparison window above, our analysis of failed tests is complete and probably, we now know the root cause of a possible bug (if it was a real case scenario).
Let me modify the test a bit and see if the test still passes, if one word is wrong in an entire verified correct sentence?
Example:
<script src=”https://gist.github.com/suparna-khamaru/41c886c287cf9835e56bd3f313a15e9c.js"></script>
On test execution, the Result Comparison display the below highlighting the unmatched section of the test result in red colour in both expected and actual result:
Is it not so simple to find out why our Junit test failed so quickly? This is why Junit is so widely used and popular in the Java community.
Let us now rerun all tests with valid test data and see how our tests pass successfully.
Let us redesign and explore the junit test class further and make our tests look elegant as well.
What are the most common widely used Junit5 Annotations?
Once we know that our basic tests are working fine. Let us explore the various annotations of Junit 5 which can help us in enhancing & optimising our test framework further.
@Test
Any method starting with @Test annotation shall be considered and identified as a test method by Junit on runtime.
Example:
<script src=”https://gist.github.com/suparna-khamaru/da055cf4beb505b4bb33933db4260b0e.js"></script>
@BeforeEach
@BeforeEach annotations are generally used to run generic steps before each of the test methods.
Example:
<script src=”https://gist.github.com/suparna-khamaru/7d332aa4486b9bd5a19bc1c97166a754.js"></script>
Where, we can observe that the ‘expected’ variable is set to ‘10’ before running each of the tests in the test class each time.
@AfterEach
Similarly, @AfterEach annotation is run after each of the tests are run on runtime. Usually the common test steps after running each test are mentioned here.
@BeforeAll
@BeforeAll annotation’s test method is static in nature and hence, the variables mentioned here are to be static in nature. It is mostly used in cases where we want to run a setUp method only once in a class before all the tests are even initiated for test run. That means, @BeforeAll is invoked even before @BeforeEach is invoked.
Example:
<script src=”https://gist.github.com/suparna-khamaru/74338c8d468f0f988f92e81ac4b30ea8.js"></script>
In the above example, we can observe that, even when @BeforeAll annotation is set for setUp method with ‘expected’ variable value of 10, the second test still considers the expected value to be zero, instead of 10, because of @AfterEach annotated value of the same in tearDown() method where the value resets to zero from ten.
@AfterAll
@AfterAll annotation also needs to have its method & variables to be static in nature. It is very similar to @BeforeAll Annotation, however the only difference between the two where it differs is that @AfterAll is used as a tearDown method and is used after all the tests in the class are run successfully.
Example:
@AfterAll
static void tearDownAll() {
// Add code that runs after all test are completely run
}
@Disabled
The usage of @Disabled annotation is to disable running of particular tests in a test suite. We can disable tests in Junit5 in two ways:
- Test method level
- Test class level
Disabling in Test method level
When a test method is disabled, and the test class is run, the test result is as shown in the below figure:
Disabling in Test class level
When a test class is disabled, all the tests in the test class are also disabled and no tests in the test class are run when the user tries to run the tests in the test class.
Example:
<script src=”https://gist.github.com/suparna-khamaru/59f798ea1a2a713e99d5150f1bbb908e.js"></script>
As a result of which, all the tests in the disabled test class are not found to be running when run and are found disabled with greyed icons beside each test, as can be observed from the figure below in the Junit test runner result area.
@DisplayName
We can display customised display names to our
- test methods and
- test classes
for our convenience, understanding and ease of reading test reports, test results and test logs.
Thus, we can use @DisplayName annotation before any test class name and/or before any test method name and when run by the test runner, we can observe that the tests are run and results are displayed as per values provided in @DisplayName annotation, as can be observed from the figure below:
@Nested
@Nested annotation provides more flexibility to execute tests in any order and in any hierarchy as per testing need.
As can be observed from the figure below,
- class Parent is nested inside class GrandParent and
- class Child is nested inside class Parent
package jUnit5; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; class GrandParent {
@Test void test1() { } @Nested class Parent {
@Test void test2() { }
@Test void test3() { }
@Test void test4() { } @Nested class Child {
@Test void test5() { }
@Test void test6() { }
@Test void test7() { }
}
}
}
Thus, during test execution, all the tests are run in the same nested order as written in the test.
@ParameterizedTest
There are different ways to parametrize test data in Junit5, let us go through one of the easiest & simplest ways of parameterising.
This annotation provides us a way to run a single test multiple times with different varieties of parameters, thus improving optimisation of test is achieved with more test coverage with minimum lines of code.
Here, instead of using @Test, we need to use @ParameterizedTest before a test method, and also provide a valid source for passing the arguments using @ValueSource annotation, as in the example below:
package jUnit5; import static org.junit.Assert.assertTrue;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; class Hello { @ParameterizedTest
@ValueSource(strings = {"kolkata", "kerala", "karnataka"})
void testPlaces(String str) {
assertTrue(str.endsWith("a") && str.startsWith("k"));
}
}
As a result of which, on running the above parameterised test, we shall observe the test result in the below manner:
@RepeatedTest
Using @RepeatedTest, we can also run the same test multiple times, to check the performance & output of the test each time for various reasons.
Example:
package jUnit5;import static org.junit.Assert.assertEquals;import org.junit.jupiter.api.DisplayName;import org.junit.jupiter.api.RepeatedTest;@DisplayName(value = “Hello”)class hello {@RepeatedTest(value = 5)void testMultipleTimes() {assertEquals(5, 3+2);}}
For which the test result post running shall be as follows:
What are the most common Assertions in Junit 5?
What are Assertions?
Assertions are usually verification test steps where test makes sure that
- Test passes as the expected test data matches with actual data &
- Test fails as the expected test data mismatches with the actual data found during running the test on runtime
As per the official documentation of Junit5, Assertions is a collection of utility methods that support asserting conditions in tests.
Let us walkthrough some of the different varieties of assertions available in Junit5:
<script src=”https://gist.github.com/suparna-khamaru/3b09c40b98a55e330b95ba7a49941b40.js"></script>
How can LambdaTest be used to run JUnit Scripts with Selenium?
When you run the below test script,
<script src=”https://gist.github.com/suparna-khamaru/e569d5127f0ae81b95bba2307daa0989.js"></script>
The test status is found executed in Lambda dashboard with required test artifacts, logs and video recording as well as the same is reflected with accurate test status in Eclipse locally as well.
How can LambdaTest be used to run JUnit Scripts for parallel test runs?
As can be observed in the figure below, the same test suite is found running and passing successfully in the LambdaTest dashboard on 3 different desktop environments which were configured in the test framework effortlessly.
Configurations passed via test framework is:
env.add(new String[]{“WIN10”, “chrome”, “70.0”});
env.add(new String[]{“macos 10.12”,”firefox”,”62.0"});
env.add(new String[]{“WIN8”,”internet explorer”,”10"});
Thanks for reading this article! Leave a comment below if you have any questions. Be sure to leave an appreciation message if my writing helped you.
Connect & Follow me:
- https://www.linkedin.com/in/suparnakhamaru/
- https://github.com/suparna-khamaru
- https://super-tester.medium.com/
About the Author:
SUPARNA KHAMARU
Works as a Mobile apps Automation & Testing— Software Principal Engineer, with several years of experience in a wide range of renowned apps.
Specialised in XCUITest — Swift and Espresso Test Frameworks and believes in configuring and setting up test pipelines to CI for fast and continuous shift-left testing.
Loves to test & automate in various platforms and is an enthusiast tech blogger.