Nowadays, many programmers in IT industry may have many excuses for not writing Unit Tests. Some of them don’t know the way to write tests and some of them will assign the testing tasks to testers. Even some of them would not admit that their code are not perfect. No matter for developer or tester, doing unit testing is very significant to ensure the quality of the software during whole SDLC process. First, Unit Testing could reduce bugs in both new and existing features in early coding stage which means reducing the risks of the product release. Second, Unit tests could help the company reduce the cost of change. A well tested code could be used in the following stages, there will not be so much changes to fix the code. What is more, Unit tests are good documentation for reusing and API development example (Eric M. & Brian M, 2003) . Also, Unit testing could help developers improve design and development. TDD is very helpful for developers to develop product with good quality and requirements satisfaction. Therefore, Unit Testing would be great choice for IT heroes. Automation tools are available for Unit Testing under different IDE environment. The main advantage of automation unit test is to test and integrate the test issues quickly and efficiently. In the article, a sample java code is provided and JUnit would be used as the tool under Eclipse environment to do the Unit Testing. Findings of the Unit Testing would be discussed and future development suggestions would be provided for Q&A in the future.
Unit testing is to test the basic component of the software. Function, method or class could be considered as the unit of the program. The unit could be considered as the smallest component of software development process. Unit testing process has two main procedures: static review and dynamic execution tracing.
Static review is the first procedure. In the process, the algorithm logics of the code would be checked. Testers would ensure the correctness, clarity, standardization and efficiency of the algorithm. The more defects discovered in the code, the lower the risks for the whole SDLC.
Executing the testing program to test the unit would be the second procedure. According to the test cases, looking for the defects by tracing and comparing the actual and expectable results.
(1) Verifying the correctness of the algorithm’s logic: Check whether the code could make the unit function well according to the requirements.
(2) Verifying the correctness of the module’s interface: Check whether the data structure, parameters and sequence are defined in the correct way. Make sure the return value is in the correct value and data type.
(3) Make sure whether the inputting data is checked: If the data is not checked, identify whether the data needs to be check. Check the data if it needs to be.
(4) Bugs processing: Identify the conditions for producing the bugs and find out the solutions to deal with the defects.
(5) Verify the correctness of the statement for code: Make sure all the mistakes of the logics and syntax would be discovered. Ensure the reliability of the code. Optimize the code and make it easier to understand.
(6) Check the use of different variables: Make sure to use the different variables with different data types and values in the correct way.
(7) Make sure the definition of the statement is standardized: The name of variables should be meaningful. Too long, too short and non-understandable names would make people confused. The names should be identified with related functionality. The meaning of names should not be duplicated or mixed.
(8) Make sure the coding style is standardized: Format and statement should be identified.
(9) Identify whether the algorithm could be optimized and reduce redundancy of the code.
(10) Check whether the code is easy to understand and make the code not too complicated.
(11) Check whether the comments of the methods are complete: Check whether the comments are clear and simplified. Make sure the reader could understand the functionality of the unit or module. Correct the wrong comments and delete the unnecessary comments if available.
Several issues should be taken into consideration for Unit Testing execution: (1) Test each independent path inside the module. (2) Test each logic decision making statement for all situation considerations, especially for Boolean logic. (3) Execute loop under the boundary value.
It is aimed to find internal defects in the module. Verify whether the code could meet the specification of the requirements. Tracing the defects of the designing requirements documentation. Looking for mistakes made during coding process and find solutions to improve coding quality and efficiency.
The documentation is used for introducing Unit Testing methodology and recording the Unit Testing findings for the given java sample code (methods: sorting increase, find maximum, and find average). Code analysis, test cases, automation code, testing results and optimization suggestions would be covered.
The main purpose for making the documentation are: 1.To have better understanding of Unit Testing. 2. Practice Junit with Eclipse java to test java sample code. 3. Help to record the defects and fix the bugs.
An array A of N integer elements are provided, the functions need to realize are as followed as below:
1- sort the elements in an ascending order
2- find the maximum value
3- find the average of the elements
N is an integer in the range of [0 .. 100]
A elements are integers in the range [-1000 .. 1000]
Selection sort. (Baidu, 2011).
Finding the Largest Number in an Unsorted List of Numbers. (RFF Electronics, 2010).
Example flowchart 1: Find the result of addition of three numbers. What about their average? (Anik’s Codepen, 2011).
public class OriginalCode {
/**
* User selection sort algorithm
*/
public int[] sortArr(int[] A, int N) {
int[] sA = A;
int swap;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
if (sA[j] < sA[i]) {
swap = sA[j];
sA[j] = sA[i];
sA[j] = swap;
}
}
}
return sA;
}
According to the diagram, the sorting method might have logic statement errors.
public int findMax(int[] A, int N) {
int max = A[0];
for (int i = 0; i < N – 1; i++) {
if (max < A[i])
max = A[i];
}
return max;
}
public int findAvg(int[] A, int N) {
int sum = 0;
int avg = 0;
for (int i = 0; i < N; i++) {
sum = +A[i];
}
avg = sum / N;
return avg;
}
public static void main(String[] args) {
OriginalCode tProj = new OriginalCode();
int[] A = { 22, 3, 55, 4, 5, 88 };
int N = A.length;
?????????????
}
}
According to the diagram, findmax method might have errors in loop statement, findavg might have strange statement and the main method is not completed.
Refine the format of the code
Generally speaking, developing code under specific IDE environment would be great choice because the IDE would offer convenient functions for developers to transfer the code into formal standard format. Adding spaces properly in the code could be achieved by pressing “Ctrl+Shift+F” under Eclipse environment. In this way, the code would be more readable for each reviewer
Locate and get the methods embedded in the main method of the program which would be tested
Most of the functions would be achieved by the methods of the program. However, in the code, it is really inconvenient to test the existing methods by adding more inputting information and displaying possible results or returned information in the original code. It is not wise to rewrite the inputting information. In this situation, extracting the methods from the code would be implemented to show the logic independently in another file. In the new method, tester would be able to re-input different parameters to test the functionality of the logic without concerning any other issues.
Rewrite the process of testing method’s logic in Unit-test format
Repeating verifying the output of each method after changing the testing data and rerunning the testing process of the methods would be time-inefficient. By creating Junit-test case, automation of verification would be easily and efficiently implemented. Class for testing different components or modules would be built. Different sub-testing methods with different inputting data would be developed.
Converting the test cases into automation unit testing code
According to the test cases those have been developed before, sub-testing methods for specific components would be extended. Different “Assertion” statement would be used for different kinds of data structure and logics.
Integrating the test cases
The reuse of code and module would be very common issue for developers and testers. It is necessary to integrate the typical automated test cases for reusing. Integrated test cases would be easier and quicker to execute. Furthermore, integrated test cases would be significant for future sanity testing and regression testing consideration. In this way, Junit test suites would be created.
Sorting
Test Case ID | Description | Input | Expected Output | Actual Output | Pass/Fail |
S-1 | The component will not sort with empty array | {} | {} | {} | P |
S-2 | The component will not sort with array contains one element | {42} | {42} | {42} | P |
S-3 | The component will sort correctly with array contains two elements | {1,2} | {1,2} | {1,2} | P |
S-4 | The component will sort with array contains two elements into inverse order | {2,1} | {1,2} | {2,1} | F |
S-5 | The component will sort correctly with array contains two same elements | {2,2} | {2,2} | {2,2} | P |
S-6 | The component will sort correctly with array contains three elements | {1,2,3} | {1,2,3} | {1,2,3} | P |
S-7 | The component will sort correctly(1st and 2nd swaped) with array contains three elements | {2,1,3} | {1,2,3} | {2,1,3} | F |
S-8 | The component will sort correctly(3rd and 2nd swaped) with array contains three elements | {1,3,2} | {1,2,3} | {1,3,2} | F |
S-9 | The component will sort with array contains three elements into inverse order | {3,2,1} | {1,2,3} | {3,2,1} | F |
S-10 | The component will sort correctly with array(contains elements with correct order) contains random elements | {-3,0,1,5,9} | {-3,0,1,5,9} | {-3,0,1,5,9} | P |
S-11 | The component will sort correctly with array(contains elements with incorrect order) contains random elements | {9,-3,5,0,1} | {-3,0,1,5,9} | {9,-3,5,0,1} | F |
Unit Testing Code:
package testcases;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import Code.TestingProj;
import static org.junit.Assert.assertArrayEquals;
import java.util.Arrays;
public class SortingTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println(“before sortingtest class”);
}
@Before
public void setUp() throws Exception {
System.out.println(“before test”);
}
@Test
public void shouldDoNothingWithEmptyArray() {
System.out.println(“test case should do nothing with empty array”);
int[] values = {};
int N = values.length;
TestingProj test = new TestingProj();
test.sortArr(values, N);
assertArrayEquals(new int[] {}, values);
}
@Test
public void shouldDoNothingWithOneElementArray() {
System.out.println(“test case should do nothing with one element array”);
int[] values = { 42 };
int N = values.length;
TestingProj test = new TestingProj();
test.sortArr(values, N);
assertArrayEquals(new int[] { 42 }, values);
}
@Test
public void sortCorrectOrderWithTwoElementArray() {
System.out.println(“test case sort correct order with two element array”);
TestingProj test = new TestingProj();
Assert.assertTrue(
Arrays.equals(new int[] { 1, 2 }, test.sortArr(new int[] { 1, 2 }, new int[] { 1, 2 }.length)));
}
@Test
public void sortInverseOrderWithTwoElementArray() {
System.out.println(“test case sort inverse order with two element array”);
TestingProj test = new TestingProj();
Assert.assertTrue(
Arrays.equals(new int[] { 1, 2 }, test.sortArr(new int[] { 2, 1 }, new int[] { 2, 1 }.length)));
}
@Test
public void sortCorrectOrderWithTwoSameElementArray() {
System.out.println(“test case sort correct order with two same element array”);
TestingProj test = new TestingProj();
Assert.assertTrue(
Arrays.equals(new int[] { 2, 2 }, test.sortArr(new int[] { 2, 2 }, new int[] { 2, 2 }.length)));
}
@Test
public void sortCorrectOrderWithThreeElementArray() {
System.out.println(“test case sort correct order with three element array”);
int[] values = { 1, 2, 3 };
int N = values.length;
TestingProj test = new TestingProj();
Assert.assertTrue(Arrays.equals(new int[] { 1, 2, 3 }, test.sortArr(values, N)));
}
@Test
public void sortFirstTwoSwapedWithThreeElementArray() {
System.out.println(“test sort first two swaped with three element array”);
int[] values = { 2, 1, 3 };
int N = values.length;
TestingProj test = new TestingProj();
Assert.assertTrue(Arrays.equals(new int[] { 1, 2, 3 }, test.sortArr(values, N)));
}
@Test
public void sortLastTwoSwapedWithThreeElementArray() {
System.out.println(“test sort last two swaped with three element array”);
int[] values = { 1, 3, 2 };
int N = values.length;
TestingProj test = new TestingProj();
Assert.assertTrue(Arrays.equals(new int[] { 1, 2, 3 }, test.sortArr(values, N)));
}
@Test
public void sortInversedOrderWithThreeElementArray() {
System.out.println(“test sort inversed order with three element array”);
int[] values = { 3, 2, 1 };
int N = values.length;
TestingProj test = new TestingProj();
Assert.assertTrue(Arrays.equals(new int[] { 1, 2, 3 }, test.sortArr(values, N)));
}
@Test
public void shouldSortValuesWithCorrectOrderRandomArray() {
System.out.println(“test sort correct order with any element array with any size”);
int[] values = { -3, 0, 1, 5, 9 };
int[] expectedOrder = { -3, 0, 1, 5, 9 };
int N = values.length;
TestingProj test = new TestingProj();
test.sortArr(values, N);
assertArrayEquals(expectedOrder, values);
}
@Test
public void shouldSortValuesWithIncorrectOrderRandomArray() {
System.out.println(“test sort incorrect order with any element array with any size”);
int[] values = { 9, -3, 5, 0, 1 };
int[] expectedOrder = { -3, 0, 1, 5, 9 };
int N = values.length;
TestingProj test = new TestingProj();
test.sortArr(values, N);
assertArrayEquals(expectedOrder, values);
}
@After
public void tearDown() throws Exception {
System.out.println(“after test”);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println(“after sorttest class”);
}
}
Find Max
Test Case ID | Description | Input | Expected Output | Actual Output | Pass/Fail |
FM-1 | The component will not work with array contains one element | {2} | 2 | 2 | P |
FM -2 | The component will not work with array contains two equal elements | {2,2} | 2 | 2 | P |
FM -3 | The component will find the max with array contains two unequal elements(1st is small) | {1,2} | 2 | 1 | F |
FM -4 | The component will find the max with array contains two unequal elements(2nd is small) | {2,1} | 2 | 2 | P |
FM -5 | The component will not work with array contains three equal elements | {2,2,2} | 2 | 2 | P |
FM -6 | The component will find the max with array contains three unequal elements(1st large) | {3,1,2} | 3 | 3 | P |
FM -7 | The component will find the max with array contains three unequal elements(2nd large) | {1,3,2} | 3 | 3 | P |
FM -8 | The component will find the max with array contains three unequal elements(3rd large) | {1,2,3} | 3 | 2 | F |
FM -9 | The component will find the max with array contains four elements(3rd large) | {1,2,3,2} | 3 | 3 | P |
FM -10 | The component will find the max with array contains four elements(4th large) | {1,2,3,8} | 8 | 3 | F |
Unit Testing Code:
package testcases;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import Code.TestingProj;
public class Findmaxtest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println(“before Findmaxtest class”);
}
@Before
public void setUp() throws Exception {
System.out.println(“before test”);
}
@Test
public void shouldDoNothingWithArrayWithSingleElement() {
System.out.println(“test case single element array”);
int[] values = { 2 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(2) == result);
}
@Test
public void shouldDoNothingWithArrayWithTwoEqualElements() {
System.out.println(“test case double equal elements array”);
int[] values = { 2, 2 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(2) == result);
}
@Test
public void findMaxWithArrayWithTwoUnequalElementsFirstSmall() {
System.out.println(“test case double unequal elements array first small”);
int[] values = { 1, 2 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(2) == result);
}
@Test
public void findMaxWithArrayWithTwoUnequalElementsSecondSmall() {
System.out.println(“test case double unequal elements array second small”);
int[] values = { 2, 1 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(2) == result);
}
@Test
public void findMaxWithArrayWithThreeEqualElements() {
System.out.println(“test case three equal elements array “);
int[] values = { 2, 2, 2 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(2) == result);
}
@Test
public void findMaxWithArrayWithThreeElementsFirstLarge() {
System.out.println(“test case three elements array first large”);
int[] values = { 3, 1, 2 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(3) == result);
}
@Test
public void findMaxWithArrayWithThreeElementsSecondLarge() {
System.out.println(“test case three elements array second large”);
int[] values = { 1, 3, 2 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(3) == result);
}
@Test
public void findMaxWithArrayWithThreeElementsThirdLarge() {
System.out.println(“test case three elements array third large”);
int[] values = { 1, 2, 3 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(3) == result);
}
@Test
public void findMaxWithArrayWithFourElementsThirdLarge() {
System.out.println(“test case four elements array third large”);
int[] values = { 1, 2, 3, 2 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(3) == result);
}
@Test
public void findMaxWithArrayWithFourElementsForthLarge() {
System.out.println(“test case four elements array forth large”);
int[] values = { 1, 2, 3, 8 };
int N = values.length;
TestingProj test = new TestingProj();
int result = test.findMax(values, N);
assertTrue(Integer.valueOf(8) == result);
}
@After
public void tearDown() throws Exception {
System.out.println(“after test”);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println(“after findmax test class”);
}
}
Find Avg
Test Case ID | Description | Input | Expected Output | Actual Output | Pass/Fail |
FA-1 | The component will not work with array contains one element | {22} | 22 | 22 | P |
FA-2 | The component will find average with array contains two unequal element | {22,88} | 55 | 44 | F |
FA-3 | The component will find average with array contains three unequal element | {22,88,66} | 58 | 22 | F |
Unit Testing Code:
package testcases;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import Code.TestingProj;
public class Findavetest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println(“before Findavetest class”);
}
@Before
public void setUp() throws Exception {
System.out.println(“before test”);
}
@Test
public void shouldDoNothingWithArrayWithSingleElement() {
System.out.println(“test case single element array”);
int[] values = { 22 };
int N = values.length;
TestingProj test = new TestingProj();
double result = test.findAvg(values, N);
assertTrue(Integer.valueOf(22) == result);
}
@Test
public void shouldFindavgWithArrayWithDoubleElement() {
System.out.println(“test case double elements array”);
int[] values = { 22, 88 };
int N = values.length;
TestingProj test = new TestingProj();
double result = test.findAvg(values, N);
assertTrue(Integer.valueOf(55) == result);
}
@Test
public void shouldFindavgWithArrayWithThreeElement() {
System.out.println(“test case three elements array”);
int[] values = { 22, 88, 66 };
int N = values.length;
TestingProj test = new TestingProj();
double result = test.findAvg(values, N);
assertTrue(Integer.valueOf(58) == result);
}
@After
public void tearDown() throws Exception {
System.out.println(“after test”);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println(“after findavetest class”);
}
}
Code for test suites:
package testcases;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ Findavetest.class, Findmaxtest.class, SortingTest.class })
public class JunitTestSuite {
}
According to the actual result, we infer that:
- The sort method could not do the sorting and swapping the elements at all.
- The find max method could not scan the capturing and comparing with the last index element, and the algorithm finishes before capturing the last index element.
- The find avg method could not sum all elements, and the algorithm just return the last index element and divide the number of the size.
From the test result, we can infer the possible defects. Those defects are exactly the defects we found during review stage. Now, go back to the code and fix the bugs.
package Code;
import java.util.Arrays;
public class TestingProj {
public int[] sortArr(int[] A, int N) {
int[] sA = A;
int swap;
for (int i = 0; i < N; i++) {
System.out.print((i + 1) + “round” + “sorting:”);
for (int j = i + 1; j < N; j++) {
if (sA[j] < sA[i]) {
swap = sA[j];
sA[j] = sA[i];
sA[i] = swap;
}
}
System.out.println(Arrays.toString(sA));
}
return sA;
}
public int findMax(int[] A, int N) {
int max = A[0];
for (int i = 0; i < N; i++) {
System.out.print((i + 1) + “time” + “find:”);
if (max < A[i])
max = A[i];
System.out.println(max);
}
return max;
}
public double findAvg(int[] A, int N) {
int sum = 0;
double avg = 0;
for (int i = 0; i < N; i++) {
System.out.print((i + 1) + “time” + “add:”);
sum += A[i];
System.out.println(sum);
}
avg = sum / N;
System.out.println(avg);
return avg;
}
public static void main(String[] args) {
{
// Initialize the class TestingProj
TestingProj test = new TestingProj();
// Assign value(array) to the parameters
int[] A = { 22, 3, 55, 4, 5, 88 };
// Define the size of the array
int N = A.length;
// Display the sorted array elements
System.out.println(Arrays.toString(test.sortArr(A, N)));
// Display the maximum value of array elements
System.out.println(test.findMax(A, N));
// Display the average value of array elements
System.out.println(test.findAvg(A, N));
}
}
}
Now, run the JUnit test suites.
We fix the bugs and all the unit test cases pass.
By doing the Unit Testing for the given java code. Defects of the three main methods are discovered. For the sorting method, the swap value should be assigned to A[i]. This way, the method could swap the values and get the maximum to the right position. For find max method, the i<N and the method could compare the last element and will not miss any element. For find avg method, the + should be put to the right side of =, if it is on the right side, it will not do anything and the value would be assigned from right to the left. Another issue is that TDD would be good way to help developers to avoid making such small mistakes during the development process.
Reference
Anik’s Codepen. (2011). Example flowchart 1: Find the result of addition of three numbers. What about their average? Retrieved from https://www.anikdas.com/blog/category/java/flowchart/
Eric M. & Brian M. (2003). Top 12 Reasons to Write Unit Tests. Retrieved from
http://www.onjava.com/pub/a/onjava/2003/04/02/javaxpckbk.html
RFF Electronics. (2010). Finding the Largest Number in an Unsorted List of Numbers. Retrieved from http://www.rff.com/find-largest-number.htm
Selection sort. (2011). In Baidu. Retrieved September 4, 2016, from http://baike.baidu.com/link?url=Nb4fyAk5K_g_ILMrrdXBTm5b-CuM_5kbBaV2G08Tg1is98z26EAkbOk3lHmOLf0yXt8QT3GZgCpYzhFET66BM
Very good and easy way to show how JUnit works with java in unit testing.
Thank you for viewing my post. Welcome to give more suggestions and constructive advice on how to do better unit testing.