Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Unit Testing | Testing in Development
Java JUnit Library. Types of Testing
course content

Course Content

Java JUnit Library. Types of Testing

Java JUnit Library. Types of Testing

1. Testing in Development
2. Unit Tests
3. Exceptions

bookUnit Testing

Let's take a closer look at the concept of unit testing and why it's necessary.

JUnit Basics

JUnit is a framework for unit testing that provides annotations for defining test methods and assertions to check expected results.

You've already encountered annotations when overriding different methods. In simple terms, annotations tell the compiler or framework what to do with a particular module. They also provide information to the programmer about the meaning of a specific line or module in the program. Annotations greatly simplify life and are used in almost every framework. Let's take a look at a simple example of a unit test, and you'll understand how annotations are used:

In this example:

  • The @Test annotation indicates that the method testAddition() is a test method;
  • Calculator is the class we are testing;
  • Assertions.assertEquals(8, result) checks that the addition result equals 8.

Therefore, we have verified that the add() method correctly performs its function. However, a single unit test is not sufficient, as there could be many other issues. For example, a user might pass null instead of a number, or the numbers could fall outside the acceptable range. Such cases should also be covered by unit tests.

Note

We will delve into writing and learning unit tests in the next section. This chapter is designed for informational purposes and to help you understand why writing unit tests is necessary.

What should unit tests check?

Let's imagine that we need to test a simple method. For this purpose, we will write a method that takes a string in the form of
"Name||Address||email||phoneNumber||" and splits it into a map with corresponding keys and values.

This method code will look something like this:

java

Main

copy
12345678910111213141516171819202122232425
package com.example; import java.util.HashMap; import java.util.Map; public class Main { public static Map<String, String> convertToMap(String input) { Map<String, String> resultMap = new HashMap<>(); String[] parts = input.split("\\|\\|"); resultMap.put("Name", parts[0]); resultMap.put("Address", parts[1]); resultMap.put("Email", parts[2]); resultMap.put("PhoneNumber", parts[3]); return resultMap; } public static void main(String[] args) { String input = "John Doe||123 Maple Street||johndoe@example.com||555-1234"; Map<String, String> result = convertToMap(input); System.out.println(result); } }

Note

To split this format, we need to split by the || symbol, but we must indicate to the compiler that it is indeed a symbol and not a command. Therefore, we use \\ before the symbol. Thus, our regex looks like this: \\|\\|.

The method is quite simple to write. But let's now return to what exactly test cases exist for this method:

  • Test of Correct Data Testing with correctly formatted input string. Expecting the method to return a Map with the correct values for each key;
  • Test of Incorrect Format Testing with a string that does not match the expected format (e.g., missing some of the required || separators or having them in excess);
  • Test of Empty String Checking the method's behavior when the input string is empty. The method should either return an empty Map or throw an exception;
  • Test of Null String Testing the method's behavior when null is passed as the input string.

Let's go step by step. In the first test case, we will test the functioning of this method with correct data. In the main method, we have already done this when we passed a value and received the correct data.

In the second test case, we need to pass an incorrect format to see how the method will behave. For example, let's pass data separated by a single | character:

java

main

copy
12345678910111213141516171819202122232425
package com.example; import java.util.HashMap; import java.util.Map; public class Main { public static Map<String, String> convertToMap(String input) { Map<String, String> resultMap = new HashMap<>(); String[] parts = input.split("\\|\\|"); resultMap.put("Name", parts[0]); resultMap.put("Address", parts[1]); resultMap.put("Email", parts[2]); resultMap.put("PhoneNumber", parts[3]); return resultMap; } public static void main(String[] args) { String input = "John Doe|123 Maple Street|johndoe@example.com|555-1234"; Map<String, String> result = convertToMap(input); System.out.println(result); } }

As you can see, we are throwing an IndexOutOfBoundsException. This means that the array we create from the original string does not have 4 elements as it should have. The test showed us that our method is not perfect, so let's add exception handling using a simple if statement:

Here, we've added a basic check that, in case incorrect data is passed, will return an empty map and print a message about the method's incorrect operation.

Let's look at a runnable example:

java

main

copy
123456789101112131415161718192021222324252627282930
package com.example; import java.util.HashMap; import java.util.Map; public class Main { public static Map<String, String> convertToMap(String input) { Map<String, String> resultMap = new HashMap<>(); String[] parts = input.split("\\|\\|"); if (parts.length != 4) { System.out.println("Input string format is not correct"); return new HashMap<>(); } resultMap.put("Name", parts[0]); resultMap.put("Address", parts[1]); resultMap.put("Email", parts[2]); resultMap.put("PhoneNumber", parts[3]); return resultMap; } public static void main(String[] args) { String input = "John Doe|123 Maple Street|johndoe@example.com|555-1234"; Map<String, String> result = convertToMap(input); System.out.println(result); } }

As you can see, the third test case is also covered by this check; If an empty string is passed, it won't pass the validation we wrote.

Let's move on to the case where a null value is passed. We don't currently check the string for null, so we need to add this check in the method:

We have added a null check, and now the method will return an empty map if null is passed to it.

Let's run this code and see the result:

java

main

copy
1234567891011121314151617181920212223242526272829303132333435
package com.example; import java.util.HashMap; import java.util.Map; public class Main { public static Map<String, String> convertToMap(String input) { if (input == null) { System.out.println("Input string can't be null!"); return new HashMap<>(); } Map<String, String> resultMap = new HashMap<>(); String[] parts = input.split("\\|\\|"); if (parts.length != 4) { System.out.println("Input string format is not correct"); return new HashMap<>(); } resultMap.put("Name", parts[0]); resultMap.put("Address", parts[1]); resultMap.put("Email", parts[2]); resultMap.put("PhoneNumber", parts[3]); return resultMap; } public static void main(String[] args) { String input = null; Map<String, String> result = convertToMap(input); System.out.println(result); } }

So, we have a refined method that handles various errors and different parameter-passing cases. We tested this method manually without using the JUnit library. However, in the next section, we will do this much faster using this library and unit tests.

Everything was clear?

How can we improve it?

Thanks for your feedback!

Section 1. Chapter 4
We're sorry to hear that something went wrong. What happened?
some-alt