001: package com.clarkware.junitperf;
002:
003: import junit.framework.AssertionFailedError;
004: import junit.framework.Test;
005: import junit.framework.TestResult;
006: import junit.extensions.TestDecorator;
007:
008: /**
009: * The <code>TimedTest</code> is a test decorator that
010: * runs a test and measures the elapsed time of the test.
011: * <p>
012: * A <code>TimedTest</code> is constructed with a specified
013: * maximum elapsed time. By default, a <code>TimedTest</code>
014: * will wait for the completion of its decorated test and
015: * then fail if the maximum elapsed time was exceeded.
016: * Alternatively, a <code>TimedTest</code> can be constructed
017: * to immediately signal a failure when the maximum elapsed time
018: * of its decorated test is exceeded. In other words, the
019: * <code>TimedTest</code> will <b>not</b> wait for its decorated
020: * test to run to completion if the maximum elapsed time is
021: * exceeded.
022: * </p>
023: * <p>
024: * For example, to decorate the <code>ExampleTest</code>
025: * as a <code>TimedTest</code> that waits for the
026: * <code>ExampleTest</code> test case to run
027: * to completion and then fails if the maximum elapsed
028: * time of 2 seconds is exceeded, use:
029: * <blockquote>
030: * <pre>
031: * Test timedTest = new TimedTest(new TestSuite(ExampleTest.class), 2000);
032: * </pre>
033: * </blockquote>
034: * or, to time a single test method, use:
035: * <blockquote>
036: * <pre>
037: * Test timedTest = new TimedTest(new ExampleTest("testSomething"), 2000);
038: * </pre>
039: * </blockquote>
040: * <p>
041: * Alternatively, to decorate the <code>ExampleTest.testSomething()</code>
042: * test as a <code>TimedTest</code> that fails immediately when
043: * the maximum elapsed time of 2 seconds is exceeded, use:
044: * <blockquote>
045: * <pre>
046: * Test timedTest = new TimedTest(new ExampleTest("testSomething"), 2000, false);
047: * </pre>
048: * </blockquote>
049: * </p>
050: *
051: * @author <b>Mike Clark</b>
052: * @author Clarkware Consulting, Inc.
053: * @author Ervin Varga
054: */
055:
056: public class TimedTest extends TestDecorator {
057:
058: private final long maxElapsedTime;
059: private final boolean waitForCompletion;
060: private boolean maxElapsedTimeExceeded;
061: private boolean isQuiet;
062:
063: /**
064: * Constructs a <code>TimedTest</code> to decorate the
065: * specified test with the specified maximum elapsed time.
066: * <p>
067: * The <code>TimedTest</code> will wait for the completion
068: * of its decorated test and then fail if the maximum elapsed
069: * time was exceeded.
070: *
071: * @param test Test to decorate.
072: * @param maxElapsedTime Maximum elapsed time (ms).
073: */
074: public TimedTest(Test test, long maxElapsedTime) {
075: this (test, maxElapsedTime, true);
076: }
077:
078: /**
079: * Constructs a <code>TimedTest</code> to decorate the
080: * specified test with the specified maximum elapsed time.
081: *
082: * @param test Test to decorate.
083: * @param maxElapsedTime Maximum elapsed time (ms).
084: * @param waitForCompletion <code>true</code> (default) to
085: * indicate that the <code>TimedTest</code> should wait
086: * for its decorated test to run to completion and then
087: * fail if the maximum elapsed time was exceeded;
088: * <code>false</code> to indicate that the
089: * <code>TimedTest</code> should immediately signal
090: * a failure when the maximum elapsed time is exceeded.
091: */
092: public TimedTest(Test test, long maxElapsedTime,
093: boolean waitForCompletion) {
094: super (test);
095: this .maxElapsedTime = maxElapsedTime;
096: this .waitForCompletion = waitForCompletion;
097: maxElapsedTimeExceeded = false;
098: isQuiet = false;
099: }
100:
101: /**
102: * Disables the output of the test's elapsed time.
103: */
104: public void setQuiet() {
105: isQuiet = true;
106: }
107:
108: /**
109: * Returns the number of tests in this timed test.
110: *
111: * @return Number of tests.
112: */
113: public int countTestCases() {
114: return super .countTestCases();
115: }
116:
117: /**
118: * Determines whether the maximum elapsed time of
119: * the test was exceeded.
120: *
121: * @return <code>true</code> if the max elapsed time
122: * was exceeded; <code>false</code> otherwise.
123: */
124: public boolean outOfTime() {
125: return maxElapsedTimeExceeded;
126: }
127:
128: /**
129: * Runs the test.
130: *
131: * @param result Test result.
132: */
133: public void run(TestResult result) {
134: //
135: // TODO: May require a strategy pattern
136: // if other algorithms emerge.
137: //
138: if (waitForCompletion) {
139: runUntilTestCompletion(result);
140: } else {
141: runUntilTimeExpires(result);
142: }
143: }
144:
145: /**
146: * Runs the test until test completion and then signals
147: * a failure if the maximum elapsed time was exceeded.
148: *
149: * @param result Test result.
150: */
151: protected void runUntilTestCompletion(TestResult result) {
152:
153: long beginTime = System.currentTimeMillis();
154:
155: super .run(result);
156:
157: long elapsedTime = getElapsedTime(beginTime);
158: printElapsedTime(elapsedTime);
159:
160: if (elapsedTime > maxElapsedTime) {
161: maxElapsedTimeExceeded = true;
162: result.addFailure(getTest(), new AssertionFailedError(
163: "Maximum elapsed time exceeded!" + " Expected "
164: + maxElapsedTime + "ms, but was "
165: + elapsedTime + "ms."));
166: result.endTest(getTest());
167: }
168: }
169:
170: /**
171: * Runs the test and immediately signals a failure
172: * when the maximum elapsed time is exceeded.
173: *
174: * @param result Test result.
175: */
176: protected void runUntilTimeExpires(final TestResult result) {
177:
178: Thread t = new Thread(new Runnable() {
179: public void run() {
180: TimedTest.super .run(result);
181:
182: // IBM's JVM prefers this instead:
183: // run(result);
184: }
185: });
186:
187: long beginTime = System.currentTimeMillis();
188:
189: t.start();
190:
191: try {
192:
193: t.join(maxElapsedTime);
194:
195: } catch (InterruptedException ignored) {
196: }
197:
198: printElapsedTime(getElapsedTime(beginTime));
199:
200: if (t.isAlive()) {
201: maxElapsedTimeExceeded = true;
202: result.addFailure(getTest(), new AssertionFailedError(
203: "Maximum elapsed time (" + maxElapsedTime
204: + " ms) exceeded!"));
205: result.endTest(getTest());
206: }
207: }
208:
209: protected long getElapsedTime(long beginTime) {
210: long endTime = System.currentTimeMillis();
211: return endTime - beginTime;
212: }
213:
214: protected void printElapsedTime(long elapsedTime) {
215: if (!isQuiet) {
216: System.out.println(toString() + ": " + elapsedTime + " ms");
217: System.out.flush();
218: }
219: }
220:
221: /**
222: * Returns the test description.
223: *
224: * @return Description.
225: */
226: public String toString() {
227: if (waitForCompletion) {
228: return "TimedTest (WAITING): " + super .toString();
229: } else {
230: return "TimedTest (NON-WAITING): " + super.toString();
231: }
232: }
233: }
|