patternjavaModerate
FiniteArrayQueue type with interface and unit tests
Viewed 0 times
withteststypeinterfaceandfinitearrayqueueunit
Problem
Doing some exercises on basic data structures, I learned about queues, and decided to roll my own to better understand how a basic queue can function. As the name indicates, this Queue is made from a finite (i.e. regular) array. The JavaDoc gives more details throughout.
All this is pretty new to me, so I'm hoping to receive criticism on any and all aspects that can be improved.
Interface & Exceptions:
FiniteArrayQueue
```
/**
* A FiniteArrayQueue can enqueue 0..N Objects, after which it must dequeue Objects to make room to enqueue
* more Objects. Objects may be dequeued from it until the queue is empty. The size of the queue cannot be changed
* after instantiation.
*/
public class FiniteArrayQueue implements Queue {
private Object[] queue;
private int capacity;
private int head;
private int tail;
/**
* Constructor.
*
* Note that in order for a FiniteArrayQueue to have a "true" capacity of N items,
* its array size must be of (N + 1) to account for not being able to overlap
* the head and tail pointers of the queue (unless the queue is empty).
* @param desiredCapacity : The maxim
All this is pretty new to me, so I'm hoping to receive criticism on any and all aspects that can be improved.
Interface & Exceptions:
public interface Queue {
public int getSize();
public boolean isEmpty();
public boolean isFull();
public void enqueue(Object obj) throws QueueFullException;
public Object dequeue() throws QueueEmptyException;
}
public class QueueEmptyException extends RuntimeException {
public QueueEmptyException() {
super();
}
public QueueEmptyException(String message) {
super(message);
}
public QueueEmptyException(String message, Throwable cause) {
super(message, cause);
}
}
public class QueueFullException extends RuntimeException {
public QueueFullException() {
super();
}
public QueueFullException(String message) {
super(message);
}
public QueueFullException(String message, Throwable cause) {
super(message, cause);
}
}FiniteArrayQueue
```
/**
* A FiniteArrayQueue can enqueue 0..N Objects, after which it must dequeue Objects to make room to enqueue
* more Objects. Objects may be dequeued from it until the queue is empty. The size of the queue cannot be changed
* after instantiation.
*/
public class FiniteArrayQueue implements Queue {
private Object[] queue;
private int capacity;
private int head;
private int tail;
/**
* Constructor.
*
* Note that in order for a FiniteArrayQueue to have a "true" capacity of N items,
* its array size must be of (N + 1) to account for not being able to overlap
* the head and tail pointers of the queue (unless the queue is empty).
* @param desiredCapacity : The maxim
Solution
On testing...
Your tests are incomplete, certainly.
Your test on
We can ask a lot of the same questions for
We can ask some questions of
How about enqueuing and dequeuing?
Your
The first assertion in
Neither of these tests test that the proper exception is thrown in the proper conditions.
I would write something called
I'd also write a test called
I'd also write a test called
And most importantly, I'd spend a LOT of time on THIS answer before you even begin to start trying to implement any of the advice from my other answer (or any other answer that addresses anything but testing).
Refactoring has a tendency to introduce regressions. Unit tests prevent regressions. Beefing up your test suite before you start refactoring is a good way to make sure you're introducing as few regressions as possible.
Your tests are incomplete, certainly.
Your test on
isEmpty only tests two conditions: a newly instantiated queue which has never had anything added to it should return true, and after adding just one thing, it should return false.- How does
isEmptydo when the queue is full?
- How does
isEmptydo when the queue has had two items added and then one removed?
- How does
isEmptydo when the queue has had two items added and then two removed?
- How does
isEmptydo when it has been filled, emptied, then filled again?
- How does
isEmptydo when our queue is instantiated with a max size of zero?
We can ask a lot of the same questions for
isFull.- How does
isFulldo with a newly instantiated queue that has never had any objects added to it?
- How does
isFulldo when we've filled it and then removed one or more objects?
- How does
isFulldo when we've filled it, removed some objects, then filled it back to capacity?
- How does
isFulldo when we create a queue with max size zero?
We can ask some questions of
getSize too. You've only tested on very specific and weird case. - Does
getSizereturn the proper value of a newly instantiated array before we've added anything to it?
- For every call to
enqueue, doesgetSizereturn the correct value? (Hint: You canassertin a loop)
- If we have a full queue, try to enqueue, catch the exception, does
getSizestill return the expected value?
- For every call to
dequeue, doesgetSizereturn the correct value?
- When we've filled, then emptied to zero, does
getSizereturn the correct value?
- If we have an empty queue, try to dequeue, catch the exception, does
getSizestill return the expected value (zero)?
How about enqueuing and dequeuing?
Your
testEnqueue is testing the wrong thing. That's asserting that getSize works.The first assertion in
testDequeue has the right idea, but the second assertion is testing that isEmpty works.Neither of these tests test that the proper exception is thrown in the proper conditions.
I would write something called
testFirstInFirstOut that runs through lots of iterations and combinations of enqueuing and dequeuing and making sure things are coming out in the order we'd expect them to come out in.I'd also write a test called
testEnqueueException to verify that when we try to enqueue into a full queue, we get an exception.I'd also write a test called
testDequeueException to verify that when we try to dequeue from a full queue, we get an exception.And most importantly, I'd spend a LOT of time on THIS answer before you even begin to start trying to implement any of the advice from my other answer (or any other answer that addresses anything but testing).
Refactoring has a tendency to introduce regressions. Unit tests prevent regressions. Beefing up your test suite before you start refactoring is a good way to make sure you're introducing as few regressions as possible.
Context
StackExchange Code Review Q#121500, answer score: 13
Revisions (0)
No revisions yet.