Unit Testing Rectangle Class Methods with JUnit
Testing Rectangle Class with JUnit
Source Code Structure
The Rectangle class under test contains dimensions, area/perimeter calculations, and a generic maximum finder with custom comparators:
import java.util.Comparator;
public class Rectangle {
private int length;
private int width;
public Rectangle(int length, int width) {
this.length = length;
this.width = width;
}
public int getLength() { return length; }
public void setLength(int length) { this.length = length; }
public int getWidth() { return width; }
public void setWidth(int width) { this.width = width; }
public int computeArea() { return length * width; }
public int computePerimeter() { return 2 * length + width; }
public String toCoordinateString() {
return "(" + length + "," + width + ")";
}
public static <T> T findMaximum(T[] array, Comparator<? super T> comparator) {
int maxIndex = 0;
for (int i = 1; i < array.length; i++) {
if (comparator.compare(array[i], array[maxIndex]) > 0) {
maxIndex = i;
}
}
return array[maxIndex];
}
public static class AreaComparator implements Comparator<Rectangle> {
@Override
public int compare(Rectangle a, Rectangle b) {
if (a.computeArea() < b.computeArea()) {
return 1;
} else if (a.computeArea() == b.computeArea()) {
return 0;
} else {
return -1;
}
}
}
public static class PerimeterComparator implements Comparator<Rectangle> {
@Override
public int compare(Rectangle a, Rectangle b) {
if (a.computePerimeter() > b.computePerimeter()) {
return 1;
} else if (a.computePerimeter() == b.computePerimeter()) {
return 0;
} else {
return -1;
}
}
}
}
Testing computeArea()
Test Design
The computeArea() method accepts two int parameters representing dimensions. Valid input are positive integers; zero and negative values are considered invalid. Invalid inputs are expected to return -1.
| Test Case | Input (length, width) | Expected Output |
|---|---|---|
| TC-01 | (3, 4) | 12 |
| TC-02 | (-3, 4) | -1 |
| TC-03 | (4, -3) | -1 |
| TC-04 | (-5, -6) | -1 |
| TC-05 | (3, 0) | -1 |
| TC-06 | (0, 4) | -1 |
| TC-07 | (0, 0) | -1 |
Test Implementation
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
@RunWith(Parameterized.class)
public class AreaTest extends TestCase {
private int dimX;
private int dimY;
private int expectedValue;
public AreaTest(int dimX, int dimY, int expectedValue) {
this.dimX = dimX;
this.dimY = dimY;
this.expectedValue = expectedValue;
}
@Parameterized.Parameters(name = "{index}: {0}*{1}={2}")
public static Iterable<Object[]> testData() {
return Arrays.asList(new Object[][] {
{ 3, 4, 12 },
{ -3, 4, -1 },
{ 4, -3, -1 },
{ -5, -6, -1 },
{ 3, 0, -1 },
{ 0, 4, -1 },
{ 0, 0, -1 }
});
}
@Test
public void verifyAreaCalculation() {
assertEquals(expectedValue, new Rectangle(dimX, dimY).computeArea());
}
}
Results
| Test Case | Input (length, width) | Expected | Actual |
|---|---|---|---|
| TC-01 | (3, 4) | 12 | 12 |
| TC-02 | (-3, 4) | -1 | -12 |
| TC-03 | (4, -3) | -1 | -12 |
| TC-04 | (-5, -6) | -1 | 30 |
| TC-05 | (3, 0) | -1 | 0 |
| TC-06 | (0, 4) | -1 | 0 |
| TC-07 | (0, 0) | -1 | 0 |
The implementation lacks input validation. Edge cases with zero or negative dimensions produce incorrect results.
Testing computePerimeter()
Test Design
Similar to area testing, the perimeter method requires validation for both parameters:
| Test Case | Input (length, width) | Expected Output |
|---|---|---|
| TC-01 | (5, 6) | 22 |
| TC-02 | (-3, 4) | -1 |
| TC-03 | (3, -4) | -1 |
| TC-04 | (-3, -4) | -1 |
| TC-05 | (3, 0) | -1 |
| TC-06 | (0, 4) | -1 |
| TC-07 | (0, 0) | -1 |
Test Implemantation
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
@RunWith(Parameterized.class)
public class PerimeterTest extends TestCase {
private int dimX;
private int dimY;
private int expectedValue;
public PerimeterTest(int dimX, int dimY, int expectedValue) {
this.dimX = dimX;
this.dimY = dimY;
this.expectedValue = expectedValue;
}
@Parameterized.Parameters(name = "{index}: 2*({0}+{1})={2}")
public static Iterable<Object[]> testData() {
return Arrays.asList(new Object[][] {
{ 5, 6, 22 },
{ -3, 4, -1 },
{ 3, -4, -1 },
{ -3, -4, -1 },
{ 3, 0, -1 },
{ 0, 4, -1 },
{ 0, 0, -1 }
});
}
@Test
public void verifyPerimeterCalculation() {
assertEquals(expectedValue, new Rectangle(dimX, dimY).computePerimeter());
}
}
Results
| Test Case | Input (length, width) | Expected | Actual |
|---|---|---|---|
| TC-01 | (5, 6) | 22 | 16 |
| TC-02 | (-3, 4) | -1 | -2 |
| TC-03 | (3, -4) | -1 | 2 |
| TC-04 | (-3, -4) | -1 | -10 |
| TC-05 | (3, 0) | -1 | 6 |
| TC-06 | (0, 4) | -1 | 4 |
| TC-07 | (0, 0) | -1 | 0 |
Two issues identified: missing input validation and incorrect formula. The implementation should use 2 * (length + width) rather than 2 * length + width.
Testing findMaximum()
Testing with AreaComparator
The generic findMaximum() method requires a comparator. The AreaComparator implementation has inverted comparison logic—returning 1 when the first area is smaller.
Test Design
| Test Case | Rectangle Array | Expected Result |
|---|---|---|
| TC-01 | (10,20), (2,65), (3,10), (6,20) | (10,20) |
| TC-02 | (-4,3), (5,-6), (-10,-10), (1,1) | (1,1) |
| TC-03 | (0,3), (6,0), (0,0), (1,1) | (1,1) |
| TC-04 | (0,3), (6,0), (0,0), (-1,-1) | null |
Note: When all rectangles in an array contain invalid dimensions, findMaximum() should return null since all computeArea() call would return -1, making all comparisons equal and selecting an invalid element.
Test Implementation
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
@RunWith(Parameterized.class)
public class MaxAreaTest extends TestCase {
private Rectangle[] rectArray;
private Rectangle expectedResult;
public MaxAreaTest(Rectangle[] rectArray, Rectangle expectedResult) {
this.rectArray = rectArray;
this.expectedResult = expectedResult;
}
@Parameterized.Parameters
public static Iterable<Object[]> testData() {
return Arrays.asList(new Object[][] {
{
new Rectangle[] {
new Rectangle(10, 20), new Rectangle(2, 65),
new Rectangle(3, 10), new Rectangle(6, 20)
},
new Rectangle(10, 20)
},
{
new Rectangle[] {
new Rectangle(-4, 3), new Rectangle(5, -6),
new Rectangle(-10, -10), new Rectangle(1, 1)
},
new Rectangle(1, 1)
},
{
new Rectangle[] {
new Rectangle(0, 3), new Rectangle(6, 0),
new Rectangle(0, 0), new Rectangle(1, 1)
},
new Rectangle(1, 1)
},
{
new Rectangle[] {
new Rectangle(0, 3), new Rectangle(6, 0),
new Rectangle(0, 0), new Rectangle(-1, -1)
},
null
}
});
}
@Test
public void verifyMaximumByArea() {
Rectangle result = Rectangle.findMaximum(rectArray, new Rectangle.AreaComparator());
String actualStr = (result != null) ? result.toCoordinateString() : "null";
String expectedStr = (expectedResult != null) ? expectedResult.toCoordinateString() : "null";
assertEquals(expectedStr, actualStr);
}
}
Results
| Test Case | Rectangle Array | Expected | Actual |
|---|---|---|---|
| TC-01 | (10,20), (2,65), (3,10), (6,20) | (10,20) | (3,10) |
| TC-02 | (-4,3), (5,-6), (-10,-10), (1,1) | (1,1) | (5,-6) |
| TC-03 | (0,3), (6,0), (0,0), (1,1) | (1,1) | (0,3) |
| TC-04 | (0,3), (6,0), (0,0), (-1,-1) | null | (0,3) |
The AreaComparator.compare() method has inverted logic—larger area should return 1, not 1 when area is smaller. Additionally, the findMaximum() method does not filter out rectangles with invalid dimensions.
Testing with PerimeterComparator
Test Design
| Test Case | Rectangle Array | Expected Result |
|---|---|---|
| TC-01 | (10,20), (2,65), (3,10), (6,20) | (2,65) |
| TC-02 | (-4,3), (5,-6), (-10,-10), (1,1) | (1,1) |
| TC-03 | (0,3), (6,0), (0,0), (1,1) | (1,1) |
| TC-04 | (0,3), (6,0), (0,0), (-1,-1) | null |
Test Implementation
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
@RunWith(Parameterized.class)
public class MaxPerimeterTest extends TestCase {
private Rectangle[] rectArray;
private Rectangle expectedResult;
public MaxPerimeterTest(Rectangle[] rectArray, Rectangle expectedResult) {
this.rectArray = rectArray;
this.expectedResult = expectedResult;
}
@Parameterized.Parameters
public static Iterable<Object[]> testData() {
return Arrays.asList(new Object[][] {
{
new Rectangle[] {
new Rectangle(10, 20), new Rectangle(2, 65),
new Rectangle(3, 10), new Rectangle(6, 20)
},
new Rectangle(2, 65)
},
{
new Rectangle[] {
new Rectangle(-4, 3), new Rectangle(5, -6),
new Rectangle(-10, -10), new Rectangle(1, 1)
},
new Rectangle(1, 1)
},
{
new Rectangle[] {
new Rectangle(0, 3), new Rectangle(6, 0),
new Rectangle(0, 0), new Rectangle(1, 1)
},
new Rectangle(1, 1)
},
{
new Rectangle[] {
new Rectangle(0, 3), new Rectangle(6, 0),
new Rectangle(0, 0), new Rectangle(-1, -1)
},
null
}
});
}
@Test
public void verifyMaximumByPerimeter() {
Rectangle result = Rectangle.findMaximum(rectArray, new Rectangle.PerimeterComparator());
String actualStr = (result != null) ? result.toCoordinateString() : "null";
String expectedStr = (expectedResult != null) ? expectedResult.toCoordinateString() : "null";
assertEquals(expectedStr, actualStr);
}
}
Results
| Test Case | Rectangle Array | Expected | Actual |
|---|---|---|---|
| TC-01 | (10,20), (2,65), (3,10), (6,20) | (2,65) | (2,65) |
| TC-02 | (-4,3), (5,-6), (-10,-10), (1,1) | (1,1) | (5,-6) |
| TC-03 | (0,3), (6,0), (0,0), (1,1) | (1,1) | (6,0) |
| TC-04 | (0,3), (6,0), (0,0), (-1,-1) | null | (6,0) |
The PerimeterComparator has correct logic, but findMaximum() still lacks validation for invalid dimensions.
Corrected Implementation
import java.util.Comparator;
public class Rectangle {
private int length;
private int width;
public Rectangle(int length, int width) {
this.length = length;
this.width = width;
}
public int getLength() { return length; }
public void setLength(int length) { this.length = length; }
public int getWidth() { return width; }
public void setWidth(int width) { this.width = width; }
public int computeArea() {
if (length > 0 && width > 0) {
return length * width;
}
return -1;
}
public int computePerimeter() {
if (length > 0 && width > 0) {
return 2 * (length + width);
}
return -1;
}
public String toCoordinateString() {
return "(" + length + "," + width + ")";
}
public static <T> T findMaximum(T[] array, Comparator<? super T> comparator) {
int maxIndex = 0;
for (int i = 1; i < array.length; i++) {
if (comparator.compare(array[i], array[maxIndex]) > 0) {
maxIndex = i;
}
}
Rectangle candidate = (Rectangle) array[maxIndex];
if (candidate.getLength() <= 0 || candidate.getWidth() <= 0) {
return null;
}
return array[maxIndex];
}
public static class AreaComparator implements Comparator<Rectangle> {
@Override
public int compare(Rectangle a, Rectangle b) {
if (a.computeArea() > b.computeArea()) {
return 1;
} else if (a.computeArea() == b.computeArea()) {
return 0;
} else {
return -1;
}
}
}
public static class PerimeterComparator implements Comparator<Rectangle> {
@Override
public int compare(Rectangle a, Rectangle b) {
if (a.computePerimeter() > b.computePerimeter()) {
return 1;
} else if (a.computePerimeter() == b.computePerimeter()) {
return 0;
} else {
return -1;
}
}
}
public static void main(String[] args) {
Rectangle[] rectArray = new Rectangle[] {
new Rectangle(10, 20), new Rectangle(2, 65),
new Rectangle(3, 10), new Rectangle(6, 20)
};
Rectangle maxByArea = findMaximum(rectArray, new AreaComparator());
Rectangle maxByPerimeter = findMaximum(rectArray, new PerimeterComparator());
if (maxByArea == null) {
System.out.println("All rectangles have invalid dimensions for area comparison");
} else {
System.out.println("Maximum area: " + maxByArea.toCoordinateString());
}
if (maxByPerimeter == null) {
System.out.println("All rectangles have invalid dimensions for perimeter comparison");
} else {
System.out.println("Maximum perimeter: " + maxByPerimeter.toCoordinateString());
}
}
}
Test Suite
Combine all test classes using JUnit Suite:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
AreaTest.class,
PerimeterTest.class,
MaxAreaTest.class,
MaxPerimeterTest.class
})
public class AllTests {
}