Progress
class was written using TDD.
Interface of this class (pseudo-code):
class Progress
constructor(title, progressLength)
getTitle() : String
getLength() : int
getCompletedSteps() : List<Integer>
getCompleted() : int
getUncompleted() : int
Please criticize from the following perspectives:
- OO design
- naming
- cleanliness
- testing
Unit tests (JUnit 3):
public class TestProgress extends TestCase {
private int progressLength;
private Integer[] completedSteps;
private Progress progress;
private Progress progressWithoutCompletedSteps;
private String title;
@Override
protected void setUp() throws Exception {
super.setUp();
title = "Tested Instance";
progressLength = 200;
progress = new Progress(title, progressLength);
completedSteps = new Integer[] { 1, 2, 10, 3 };
for (Integer step : completedSteps) {
progress.complete(step);
}
progressWithoutCompletedSteps = new Progress("Title", 100);
}
public void testConstructorSetsFieldsCorrectly() {
assertEquals(title, progress.getTitle());
assertEquals(progressLength, progress.getLength());
}
public void testConstructorThrowsExceptionIfTitleIsNull() {
checkThrowsIllegalArgumentException(new Runnable() {
@Override
public void run() {
String failTitle = null;
new Progress(failTitle, 100);
}
});
}
private void checkThrowsIllegalArgumentException(Runnable runnable) {
try {
runnable.run();
fail("Missing exception");
} catch (IllegalArgumentException e) {
// all right
} catch (Exception e) {
fail("Type of exception should be IllegalArgumentException");
}
}
public void testConstructorThrowsExceptionIfProgressLengthLessThanOne() {
checkThrowsIllegalArgumentException(new Runnable() {
@Override
public void run() {
int failProgressLength = 0;
new Progress("Title", failProgressLength);
}
});
}
public void testGetCompletedSteps() {
List<Integer> expectedCompletedSteps = Arrays.asList(completedSteps);
assertEquals(expectedCompletedSteps, progress.getCompletedSteps());
}
public void testGetCompletedStepsOfProgressWithoutCompletedSteps() {
List<Integer> noCompletedSteps = new ArrayList<Integer>();
assertEquals(noCompletedSteps, progressWithoutCompletedSteps.getCompletedSteps());
}
public void testGetCompleted() {
int expectedCompleted = sumOf(completedSteps);
assertEquals(expectedCompleted, progress.getCompleted());
}
private int sumOf(Integer[] numbers) {
int sum = 0;
for (Integer each : numbers) {
sum += each;
}
return sum;
}
public void testGetCompletedOfProgressWithoutCompletedSteps() {
int expectedCompleted = 0;
assertEquals(expectedCompleted, progressWithoutCompletedSteps.getCompleted());
}
public void testGetUncompleted() {
int expectedUncompleted = progressLength - sumOf(completedSteps);
assertEquals(expectedUncompleted, progress.getUncompleted());
}
public void testGetUncompletedOfProgressWithoutCompletedSteps() {
int expectedUncompleted = progressWithoutCompletedSteps.getLength();
assertEquals(expectedUncompleted, progressWithoutCompletedSteps.getUncompleted());
}
}
Progress class:
public class Progress {
private final String title;
private final int length;
private int completed;
private List<Integer> completedSteps;
public Progress(String title, int progressLength) {
checkArguments(title, progressLength);
this.title = title;
this.length = progressLength;
this.completedSteps = new ArrayList<Integer>();
this.completed = 0;
}
private void checkArguments(String title, int progressLength) {
if (title == null) {
throw new IllegalArgumentException("Illegal title: <" + title + ">");
}
if (progressLength < 1) {
throw new IllegalArgumentException("Illegal progress length: <" + progressLength + ">");
}
}
public String getTitle() {
return title;
}
public int getLength() {
return length;
}
public void complete(int lengthToComplete) {
completedSteps.add(lengthToComplete);
completed += lengthToComplete;
}
public List<Integer> getCompletedSteps() {
return completedSteps;
}
public int getCompleted() {
return completed;
}
public int getUncompleted() {
return length - completed;
}
}
UPDATE:
In addition to what is written.
In your opinion, is the following version of the constructor better than the one already shown?
public Progress(String title, int progressLength) {
this.title = title;
this.length = progressLength;
this.completedSteps = new ArrayList<Integer>();
this.completed = 0;
checkInitState();
}
private void checkInitState() {
if (title == null) {
throw new IllegalArgumentException("Illegal title: <" + title + ">");
}
if (progressLength < 1) {
throw new IllegalArgumentException("Illegal progress length: <" + progressLength + ">");
}
}
Or I should not check the correctness of the arguments in the constructor? Maybe it would be better if the obligation to ensure the correctness of the arguments entrust to the client?