JUnit testing. Examples
Contents
- 1. The concept of unit testing in Java
- 2. The notion of Test Case. A class containing test cases (methods). Test run
- 3. An example demonstrating the use of JUnit to validate a quadratic equation solution. Step-by-step instruction
- 4. An example showing the sequence of method calls in a JUnit test
- Related topics
Search other resources:
1. The concept of unit testing in Java
In Java programming systems, including Java Eclipse, testing tools have been introduced that provide for the creation and use of automated tests for the developed programs. Correctly constructed testing allows you to reduce the number of errors in the program to zero.
The TDD (Test Driven Development) methodology is popular in the development of modern software systems. The main idea of using TDD is that first tests are developed for the desired behavior of a program (system), and then a working program code is written, which is checked by the already created tests using refactoring tools. As a result, pre-prepared tests allow you to avoid putting into operation a program containing errors.
For testing, Java Eclipse uses what is called JUnit testing, which is the de facto standard for testing Java applications. JUnit is a common framework for writing tests as Java classes. These classes can be run as a unit using the test runner.
JUnit has many extensions that are implemented in all modern Java development environments. Today JUnit is used in such directions as:
- unit testing;
- website testing;
- automatic substitution of interfaces for testing;
- testing parallel execution of applications;
- performance testing.
JUnit testing is used by many quality assurance teams on purpose-built websites that automate the application of end-to-end functional tests. In Java Eclipse, using the JUnit engine does not require a running application server or a live database.
⇑
2. The notion of Test Case. A class containing test cases (methods). Test run
When using the JUnit engine, two main units (classes) are considered:
- the class whose methods need to be tested;
- a class that represents a JUnit test. This class is built according to special rules.
This means that a JUnit test is a specially designed class containing methods that test the code of other classes. In Java Eclipse, this class is created using the JUnit Test Case command (see examples below).
The class contains a number of methods. Each of the methods of the testing class is treated as a separate test case – Test Case.
Test cases (methods) of a JUnit class can be declared using the following annotations (Java version Eclipse 2018-09 is considered):
- @BeforeAll – static method (test case), declared with this instruction, is called at the beginning of testing;
- @AfterAll – the static method declared with this instruction is called at the end of testing. Here you can set, for example, the release of resources used during testing;
- @Test – the method that is declared with this instruction is a test case. It contains directly the testing code. This method uses the class org.junit.jupiter.api.Assertions methods. This method uses comparison methods that start with the assert*() prefix. For example, the overloaded assertEquals() method is used to compare two values of any primitive type. One JUnit test class can have an arbitrary number of test methods (examples), which are declared with the @Test annotation;
- @BeforeEach – called before calling each test case (method), which is declared with the @Test annotation;
- @AfterEach – called after the completion of each test case (method) that is declared with the @Test annotation.
An arbitrary number of methods are allowed with all of the above annotations.
In the most general case, an example of a class generated by the Java Eclipse system might look like this
class TestClass { @BeforeAll static void setUpBeforeClass() throws Exception { } @AfterAll static void tearDownAfterClass() throws Exception { } @BeforeEach void setUp() throws Exception { } @AfterEach void tearDown() throws Exception { } @Test void testMethod() { fail("Not yet implemented"); } }
In the testMethod() method, you need to insert your own code for the methods of another class (see examples below). After that, you can run the test using a dedicated Java Eclipse command.
⇑
3. An example demonstrating the use of JUnit to validate a quadratic equation solution. Step-by-step instruction
3.1. Task
Using JUnit technology, develop a Unit test to test the operation of the SquareEquation class, which contains tools for solving a quadratic equation. The test should be located in the SquareEquationTest class and contain appropriate methods to validate the resulting solution.
Quadratic roots are returned as an instance of the Roots class. Class SquareEquationTest comprises appropriate means solve the quadratic equation.
⇑
3.2. Solution
3.2.1. Creating the SquareEquation and Roots classes
Before creating the classes, the project is created in the standard Java Eclipse way. Two classes named SquareEquation and Roots are added to the project and the code for these classes is generated. The SquareEquation.java file is created accordingly. After the completed actions, the Java Eclipse window looks as shown in Figure 1.
Figure 1. Java Eclipse window. Classes Roots and SquareEquation
Classes have the following purpose:
- Roots – used to save the roots of a quadratic equation (x1, x2) if the equation has these roots;
- SquareEquation – implements methods for solving a quadratic equation.
The SquareEquation class has the following components:
- internal variables a, b, c which are the coefficients of the quadratic equation;
- constructor, initializes the values of the internal fields a, b, c;
- the Solution() method, which returns an instance of the Roots class if the equation has roots. If the equation has no roots, the ArithmeticException is thrown.
The full text of the Roots and SquareEquation classes looks like this
// The roots of the equation class Roots { public double x1; public double x2; } // Class that solves the quadratic equation - this class will be tested by another class. // a*x^2 + b*x + c = 0 public class SquareEquation { // The coefficients of the equation private double a, b, c; // Constructor public SquareEquation(double a, double b, double c) { this.a = a; this.b = b; this.c = c; } // The method of solving the quadratic equation public Roots Solution() { // Discriminant double d = b*b - 4*a*c; // Checking if the equation has roots if (d<0) throw new ArithmeticException("Solution has no roots."); // Calculate the result Roots result = new Roots(); result.x1 = (-b - Math.sqrt(d)) / (2*a); result.x2 = (-b + Math.sqrt(d)) / (2*a); // Return the result return result; } }
After creating the classes, you can proceed to creating a Unit-test.
⇑
3.2.2. Creating the class needed to implement JUnit testing
To create a Unit test in Java Eclipse, you need to select a sequence of commands
File->New->JUnit Test Case
as shown in Figure 2.
Figure 2. Command to create Unit-test in Java
As a result, the “New JUnit Test Case” window will open (Figure 3) in which you need to specify the necessary information about the test.
Figure 3. New test creation window. Specifying test parameters
When creating a window, the system will automatically fill in some fields. The window displays the following information.
- The Source Folder field specifies the name of the folder with the source files of the project. The system automatically “pulls up” the name of the folder with the current project.
- In the Name field, specify the name of the class in which the test methods will be placed (with the annotations @BeforeAll, @Test, etc.). In our case, SquareEquationTest is offered (the Test suffix is added to the SquareEquation class name). The proposed name can be left unchanged.
- In the field “Which method stubs would you like to create?” the options are used to specify the methods to be generated in the class. According to the selected option, the following methods are generated:
- setUpBeforeClass() – the name of the @BeforeAll annotation method (see item 2);
- setUp() – the name of the @BeforeEach annotation method;
- tearDownAfterClass() – the name of the @AfterAll annotation method;
- tearDown() – the name of the @AfterEach annotation method.
For our test, it is enough to activate only one setUp() field. This will add an @BeforeEach annotation method that will be called before the test. This method will instantiate the SquareEquation class (see codes below).
- In the “Class under test:” field, specify the name of the SquareEquation class whose methods you want to test.
- Additionally, other options are set:
- selection of the testing model “New JUnit Jupiter test”;
- the ability to add comments;
- other.
In our case, you can leave everything unchanged.
After selecting the “Next >” button, the following window “New JUnit Test Case” will open in which you need to specify a list of methods that will be tested. The window view is shown in Figure 4. Selected methods will be declared with @Test annotation. These are directly test cases. All other options in the window can be left as default and go further with the Finish button.
Figure 4. The choice of methods to be tested. The Solution() method is selected
⇑
3.2.3. Program code of SquareEquationTest class
After creating the JUnit test using the Java window interface, Eclipse generates the code for the SquareEquationTest class
import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class SquareEquationTest { @BeforeEach void setUp() throws Exception { } @Test void testSolution() { fail("Not yet implemented"); } }
In this code, two methods are generated:
- the setUp() method with the @BeforeEach annotation. This method will be called first when testing;
- method testSolution() with the annotation @Test. In this method, the test of the Solution() function of the SquareEquation class will be placed directly.
⇑
3.2.4. Modification of the SquareEquationTest class. Test programming
To test the operation of the SquareEquation class, you need to create an instance of this class. Therefore, in the text of the SquareEquationTest class, a reference to the SquareEquation class is additionally introduced.
class SquareEquationTest { private SquareEquation se; ... }
Then, in the setUp() method, an instance of the SquareEquation class is instantiated
@BeforeEach void setUp() throws Exception { // This method is called first. // Create an instance of the SquareEquation class. se = new SquareEquation(2, 1, -3); // 2*x^2 + x - 3 = 0 }
After that, in the TestSolution() method, the code for checking the correctness of the obtained solution for the given coefficients is entered
a = 2 b = 1 c = -3
in the se instance
@Test void testSolution() { // Declare an instance of the Roots class Roots rt = se.Solution(); // Solution check x1 assertEquals(rt.x1, -1.5); // Solution check x2 assertEquals(rt.x2, 1.0); }
The solution is verified using the overloaded assertEquals() method of the org.junit.jupiter.api.Assertions class. The solution in the variables rt.x1 and rt.x2 is compared with the previously calculated (manually) solution of the current variant (a = 2, b = 1, c = -3) of the quadratic equation. If there is a match, then the decision is correct. The system needs to tell the system that the decision is correct after starting the test (next point).
In general, the text of the entire testing unit is as follows
import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class SquareEquationTest { // A reference to the SquareEquation class private SquareEquation se; @BeforeEach void setUp() throws Exception { // This method is called first. // Create an instance of the SquareEquation class se = new SquareEquation(2, 1, -3); // 2*x^2 + x - 3 = 0 } @Test void testSolution() { // Declare an instance of the Roots class Roots rt = se.Solution(); // Solution check x1 assertEquals(rt.x1, -1.5); // Solution check x2 assertEquals(rt.x2, 1.0); } }
⇑
3.3. Running the test using Java Eclipse. Viewing the test result
After the code for the SquareEquationTest class is generated, the developed test can be run for execution. This is done by the commands
Run -> Run As -> JUnit Test
or by calling the sequence of key combinations Alt + Shift + X, T as shown in Figure 5.
Figure 5. Running a JUnit Test
There is another way using the quick menu command (Figure 6).
Figure 6. Command to run JUnit test
After starting Java Eclipse, the test result will be displayed in the JUnit window on the left side (Figure 7).
Figure 7. Testing result
As you can see from the result, the confirmation of the correct decision was received, that is, the test was passed. This means that the Solution() method of the SquareEquation class gives the correct result for the case when a = 2, b = 1, c = -3. If in the TestSolution() method, when calling assertEquals(), you specifically specify an incorrect answer, for example
assertEquals(rt.x2, 777.777);
then after re-running the test, an error will be displayed in the JUnit window, as you can see in Figure 8. Although this is not a program error, but a deliberate error in the test.
Figure 8. Demonstration of test failure
⇑
4. An example showing the sequence of method calls in a JUnit test
Let a Java Eclipse system create a class named TestClass to test some other class. In this example, the essence of the class under test is irrelevant.
The program code of the class is as follows
import static org.junit.jupiter.api.Assertions.*; 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.Test; class TestClass { @BeforeAll static void setUpBeforeClass() throws Exception { System.out.println("BeforeAll"); } @BeforeAll static void setUpBeforeClass2() throws Exception { System.out.println("BeforeAll2"); } @AfterAll static void tearDownAfterClass() throws Exception { System.out.println("AfterAll"); } @BeforeEach void setUp() throws Exception { System.out.println("BeforeEach"); } @BeforeEach void setUp2() throws Exception { System.out.println("BeforeEach2"); } @AfterEach void tearDown() throws Exception { System.out.println("AfterEach"); } @Test void testSolution() { System.out.println("Test"); } @Test void testSolution2() { System.out.println("Test2"); } }
After running the test for execution, the program will give the following result
BeforeAll BeforeAll2 BeforeEach2 BeforeEach Test AfterEach BeforeEach2 BeforeEach Test2 AfterEach AfterAll
After analyzing this result, you can conclude that the methods in the test class are called in the order defined by their annotations. The @BeforeAll annotation methods are called first.
The following are test cases declared with the @Test annotation. All methods with @BeforeEach annotation are called before each test case. After each test case, all @AfterEach annotated methods are called.
All methods with @AfterAll annotation are called last.
⇑
Related topics
⇑