Unit tests are a great tool to have in every programmer’s toolbox. In this post, I’ll show an example of how to write a unit test to make sure your code for reading from a text file works properly.
Let’s say we have two classes already implemented: Laptop and Lenovo.
The class Laptop handle the information related to laptops and the class Lenovo represents the company that sells laptops.
Table of Contents
- Starting code for this example
- Implementing readFromFileMethod
- Writing the unit test for the text file reading method
Starting code for this example
See below the code for the class Laptop.
class Laptop{
private String model;
private int screenSize;
private float price;
Laptop(String model, int size, float price){
this.model = model;
this.screenSize = size;
this.price = price;
}
public float getPrice(){
return price;
}
@Override
public String toString() {
return model+", " + screenSize + ", " + price;
}
}
Find a partial implementation of the class Lenovo below.
public class Lenovo{
private Laptop laptops[];
private int numberOfLaptops;
public Lenovo(int maxLaptops){
laptops = new Laptop[maxLaptops];
numberOfLaptops = 0;
}
public void addLaptop(Laptop laptop){
laptops[numberOfLaptops] = laptop;
numberOfLaptops ++;
}
public void saveToFile(String filename) throws IOException{
File f = null;
PrintWriter pw = null;
try {
f = new File(filename);
pw = new PrintWriter(f);
for (int index = 0; index < numberOfLaptops; index++) {
pw.println(laptops[index].toString());
}
} catch (Exception e) {
// Here I just rethrow the exception to be
// handled by the caller
throw e;
}finally{
if (pw!=null)
pw.close();
}
}
public void readFromFile(String filename) throws IOException{
// Implement this method
}
}
Our job is to implement the method readFromFile and write a unit test for it.
Implementing readFromFileMethod
To implement the method readFromFile, we need first to know how the data was saved into the file.
That’s the reason why we need to have the implementation of the method saveToFile. So we can know how the data is structured in the file.
First, from the implementation above we can see it is a text file, which is important because is not the same to read from a text file as from a binary file. Also, the use of “println” tells us that in the file, we can see each object state in one line of the file.
The second part is that the method uses the string representation (toString method) of the object laptop to save it to the file.
Look at the method toString in the class laptop. We can see that in the file, first will appear the model, then a comma “,”, after that the screen size, then another comma, and lastly the price. See the code below.
@Override
public String toString() {
return model+", " + screenSize + ", " + price;
}
If you save to a file some information, and then open it, you will see something similar to the picture below.
Now we know what the file looks like. Let’s implement a method to read from that file and create new objects with the information.
public void readFromFile(String filename) throws IOException{
File f = null;
Scanner scanner = null;
try {
f = new File(filename);
scanner = new Scanner(f);
//Initialize the array to have 0 laptops
//you can change this behavior by assuming that every time
//you read from the file, you add to the current laptops
numberOfLaptops = 0;
String line;
String [] data;
Laptop l;
while (scanner.hasNext()){
line = scanner.nextLine();
data = line.split(", ");
l = new Laptop(data[0], Integer.parseInt(data[1]), Float.parseFloat(data[2]));
addLaptop(l);
}
} catch (Exception e) {
// Here I just rethrow the exception to be
// handled by the caller
throw e;
}finally{
if (scanner!=null)
scanner.close();
}
}
As you can see within the while loop, we are using the fact that we know how the data is stored in the file.
If we don’t follow the same structure that was created when we save the data to the file, then we will get exceptions.
Writing the unit test for the text file reading method
For the unit test, we are going to save first to a file (assuming that method was properly tested). After that, then read from the saved file. After that, we need to check if all the information was read.
So, we first create a company object, add laptop objects, and save them to a file.
After we save the objects, we create a new company object, so we make sure it is a brand new object, then we read the same file we saved, and the number of laptops should be the same as what we saved.
See the code below.
public class LenovoTest {
/**
* Unit tests for the Lenovo class
*/
@Test
public void readFromFile(){
Lenovo company = new Lenovo(100);
company.addLaptop(new Laptop("Laptop1", 15, 4500));
company.addLaptop(new Laptop("Laptop2", 14, 4000));
try {
company.saveToFile("laptops.txt");
company = new Lenovo(100);
company.readFromFile("laptops.txt");
} catch (Exception e) {
//handle exception
}
assertEquals(2, company.numberOfLaptops());
}
}
When I execute this unit test using visual studio code, I get the following result.
As you should remember, when we write unit tests it is very important to cover all possible cases, especially the extreme cases.
So, for you to practice you can add tests for the case there are no laptop objects within the company, the file we are trying to read does not exist, and any other situation you can think of.
If you only write the tests for the obvious cases, your code might not work properly in all the cases.
H@ppy coding!
Related posts: