In this project, you will write JUnit test cases for our code. In this case, our code will be an implementation of the Observer pattern.
You should begin by reviewing course material on the Observer
Pattern. The code you will test is a modification of Java 1.5's
observer pattern classes from
java.util
. The specification for these classes is given in the
detailed specification. Here are highlights of
the differences:
Observable
is an interface, rather than a class.
Observable
and
Observer
have been parameterized, using generics, by the type of data that is
passed to the
Observer.update
method. This obviates the need for dynamic downcasts within
Observer.update
.
Observer
with
addObserver
, you must pass a
Filter
object. Only if the
valid
method of this object returns true when given the updated state will
the associated observer be notified. You can pass a TrueFilter
if you don't want any object filtered out.
setChanged
and
hasChanged
methods. To notify the observers, simply call one of the
notifyObservers
methods directly.
NewsSimulatorParser
NewsSimulator
,
NewsSimulator
Observable
Person
Observer
interface;
Newspaper
Observerable
and received by the
update
method of
Person
.
Observable
and
NewsSimulator
meet their specifications (we will provide implementations of
Person
and
Newspaper
). In particular, you must supply us with a class
AcceptenceTests
that extends
junit.framework.TestCase.
Inside this class you will write JUnit test cases to test
implementations of the specification. Here is a skeleton for the
class you will write:
public class AcceptenceTests extends TestCase {
public void testCase1() { ... } // feel free to use more informative names
public void testCase2() { ... }
...
}
This class will contain one public, no-argument,
void
-returning method for each test that you write, and each method's
name must begin with the word
test
(all lowercase). Recall that by following this convention, JUnit
can automatically create a test suite from your
AcceptenceTests
class. Each test should be self-contained, with no dependency to
other tests. Do not use
static
fields. You may want to use
setUp
and/or
tearDown
methods. You may also define other methods in AcceptenceTests and
even helper classes (under the
cmsc433.observer
package) as necessary. Be careful not to create your own classes
that mask the JUnit classes. For example, a class called
Test
(in a source file
Test.java
) could cause problems.
Your tests should not directly construct any implementation of the
Observable
NewsSimulator
classes. Instead, use
TestFactory.getObservable()
to retrieve an object implementing
Observable
that is to be tested; and use
TestFactory.getNewsSimulator()
to retrieve an object implementing
NewsSimulator
that is to be tested.
The initial project code contains one correct implementation of
Observable
and
NewsSimulator
under the
cmsc433.observer.correct
package, and three buggy implementations under the
cmsc433.observer.buggy1
,
cmsc433.observer.buggy2
, and
cmsc433.observer.buggy3
packages. In these packages, the
Observable
implementation has one of the following flaws:
notifyObservers()
call does not notify an observer that previously registered.
deleteObserver(o)
call does not remove an observer
o
, which was previously registered.
notifyObservers(p)
call ignores any registered filters (always updates).
PublicTests
check two things: (1) that all of your test cases (in AcceptenceTests)
pass the correct implementation; (2) that at least one of your test
cases fails on each of the sample bad implementations. The release
tests will do the same thing, but on implementations with flaws you
have not seen. Therefore, try not peeking at the bad
implementations and see if you can write test cases that fail on
the three flaws.
Be systematic in building your tests. You will probably want to create a set of tests for each public method of the classes to be tested. For each of these sets you will probably have one test for each possible outcome, possible erroneous input, etc.
Finally, you can assume that all testing and implementations are
single-threaded. I.e., you don't have to worry about an
Observable
notifying an
Observer
in a separate thread.
Do not change any of the implementations. The only code you should write is test cases and additional buggy implementations that you might want to use to test your test cases.
We will grade your assignment by running your test suite on a
series of 24 additional buggy implementations and 2 additional good implementations of
Observable
and
NewsSimulator
; three buggy implementations are provided to you and tested by the public tests.
Since you only have to have at least one test case that finds a particular bug, when you are writing test cases you don't need to recheck for things that other cases handle. For example, once you've written test cases that check the addObserver method of Observable, your other tests can assume that addObserver works correctly: If it does for a particular buggy version, then your assumption is correct, and if not, the other test cases will find the problem.
For each buggy implementation, you will receive credit for finding that bug if (and only if) you have at least one test in your test suite that both passes our correct implementation(s) and fails the buggy implementation. In other words, writing a test case that simply fails all implementations will not get you any points. Put another way: In order to count for anything, your test cases must pass the correct implementation. Your test cases must also pass any other implementation that satisfies the specification. Thus we may also discount test cases that fail a different correct implementation than the one provided.
You should write test cases keeping in mind that the buggy
implementations are buggy in ways that could happen in real life.
We have not put in malicious things, like making a method fail on
exactly the 4,237th call to
addObserver
, for example.
cmsc433.observer.correct
, there's a chance that our implementation still contains bugs. As
an incentive for starting the project early, the first person to
report a particular implementation bug to us will receive 5 extra
points, for a maximum of 15 bonus points per person.
You should report these extra-credit bugs by posting them on
the Class forum.