Java Reference
In-Depth Information
thread is associated, so some work may be required to relay success or failure information
back to the main test runner thread so it can be reported.
For the conformance tests for
java.util.concurrent
, it was important that failures
be clearly associated with a specific test. Hence the JSR 166 Expert Group created a base
convention that every test must wait until all the threads it created terminate. You may not
need to go to such lengths; the key requirements are that it be clear whether the tests passed
and that failure information is reported somewhere for use in diagnosing the problem.
If a method is supposed to block under certain conditions, then a test for that behavior should
succeed only if the thread does
not
proceed. Testing that a method blocks is similar to testing
that a method throws an exception; if the method returns normally, the test has failed.
Testing that a method blocks introduces an additional complication: once the method suc-
cessfully blocks, you have to convince it somehow to unblock. The obvious way to do this
is via interruption—start a blocking activity in a separate thread, wait until the thread blocks,
interrupt it, and then assert that the blocking operation completed. Of course, this requires
your blocking methods to respond to interruption by returning early or throwing
Inter-
ruptedException
.
The “wait until the thread blocks” part is easier said than done; in practice, you have to make
an arbitrary decision about how long the few instructions being executed could possibly take,
and wait longer than that. You should be prepared to increase this value if you are wrong (in
which case you will see spurious test failures).
Listing 12.3
shows an approach to testing blocking operations. It creates a “taker” thread that
attempts to
take
an element from an empty buffer. If
take
succeeds, it registers failure.
The test runner thread starts the taker thread, waits a long time, and then interrupts it. If the
taker thread has correctly blocked in the
take
operation, it will throw
InterruptedEx-
ception
, and the
catch
block for this exception treats this as success and lets the thread
exit. The main test runner thread then attempts to
join
with the taker thread and verifies that
the join returned successfully by calling
Thread.isAlive
; if the taker thread responded
to the interrupt, the
join
should complete quickly.
The timed
join
ensures that the test completes even if
take
gets stuck in some unexpected
way. This test method tests several properties of
take
—not only that it blocks but that, when
interrupted, it throws
InterruptedException
. This is one of the few cases in which