2
2
3
3
import org .junit .AssumptionViolatedException ;
4
4
import org .junit .runner .Description ;
5
+ import org .junit .runners .model .Statement ;
5
6
6
7
import java .util .concurrent .TimeUnit ;
7
8
13
14
*
14
15
* <pre>
15
16
* public static class StopwatchTest {
16
- * private static final Logger logger= Logger.getLogger("");
17
+ * private static final Logger logger = Logger.getLogger("");
17
18
*
18
- * private static void logInfo(String testName, String status, long nanos) {
19
+ * private static void logInfo(Description description, String status, long nanos) {
20
+ * String testName = description.getMethodName();
19
21
* logger.info(String.format("Test %s %s, spent %d microseconds",
20
- * testName, status, Stopwatch .toMicros(nanos)));
22
+ * testName, status, TimeUnit.NANOSECONDS .toMicros(nanos)));
21
23
* }
22
24
*
23
25
* @Rule
24
- * public Stopwatch stopwatch= new Stopwatch() {
26
+ * public Stopwatch stopwatch = new Stopwatch() {
25
27
* @Override
26
28
* protected void succeeded(long nanos, Description description) {
27
- * logInfo(description.getMethodName() , "succeeded", nanos);
29
+ * logInfo(description, "succeeded", nanos);
28
30
* }
29
31
*
30
32
* @Override
31
33
* protected void failed(long nanos, Throwable e, Description description) {
32
- * logInfo(description.getMethodName() , "failed", nanos);
34
+ * logInfo(description, "failed", nanos);
33
35
* }
34
36
*
35
37
* @Override
36
38
* protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
37
- * logInfo(description.getMethodName() , "skipped", nanos);
39
+ * logInfo(description, "skipped", nanos);
38
40
* }
39
41
*
40
42
* @Override
41
43
* protected void finished(long nanos, Description description) {
42
- * logInfo(description.getMethodName() , "finished", nanos);
44
+ * logInfo(description, "finished", nanos);
43
45
* }
44
46
* };
45
47
*
63
65
* <pre>
64
66
* @Test
65
67
* public void performanceTest() throws InterruptedException {
66
- * long delta= 30;
68
+ * long delta = 30;
67
69
* Thread.sleep(300L);
68
70
* assertEquals(300d, stopwatch.runtime(MILLISECONDS), delta);
69
71
* Thread.sleep(500L);
74
76
* @author tibor17
75
77
* @since 4.12
76
78
*/
77
- public class Stopwatch extends TestWatcher {
78
- private long startNanos ;
79
- private long endNanos ;
79
+ public abstract class Stopwatch implements TestRule {
80
+ private final Clock clock ;
81
+ private volatile long startNanos ;
82
+ private volatile long endNanos ;
83
+
84
+ public Stopwatch () {
85
+ this (new Clock ());
86
+ }
87
+
88
+ Stopwatch (Clock clock ) {
89
+ this .clock = clock ;
90
+ }
80
91
81
92
/**
93
+ * Gets the runtime for the test.
94
+ *
82
95
* @param unit time unit for returned runtime
83
96
* @return runtime measured during the test
84
97
*/
85
98
public long runtime (TimeUnit unit ) {
86
- return unit .convert (currentNanoTime () - startNanos , TimeUnit .NANOSECONDS );
99
+ return unit .convert (getNanos () , TimeUnit .NANOSECONDS );
87
100
}
88
101
89
102
/**
@@ -110,66 +123,61 @@ protected void skipped(long nanos, AssumptionViolatedException e, Description de
110
123
protected void finished (long nanos , Description description ) {
111
124
}
112
125
113
- /**
114
- * @param nanos time in nanoseconds
115
- * @return time converted to microseconds
116
- */
117
- public static long toMicros (long nanos ) {
118
- return TimeUnit .NANOSECONDS .toMicros (nanos );
119
- }
120
-
121
- /**
122
- * @param nanos time in nanoseconds
123
- * @return time converted to milliseconds
124
- */
125
- public static long toMillis (long nanos ) {
126
- return TimeUnit .NANOSECONDS .toMillis (nanos );
127
- }
128
-
129
- /**
130
- * @param nanos time in nanoseconds
131
- * @return time converted to seconds
132
- */
133
- public static long toSeconds (long nanos ) {
134
- return TimeUnit .NANOSECONDS .toSeconds (nanos );
135
- }
136
-
137
126
private long getNanos () {
138
- return endNanos - startNanos ;
127
+ if (startNanos == 0 ) {
128
+ throw new IllegalStateException ("Test has not started" );
129
+ }
130
+ long currentEndNanos = endNanos ; // volatile read happens here
131
+ if (currentEndNanos == 0 ) {
132
+ currentEndNanos = clock .nanoTime ();
133
+ }
134
+
135
+ return currentEndNanos - startNanos ;
139
136
}
140
137
141
138
private void starting () {
142
- startNanos = currentNanoTime ();
139
+ startNanos = clock .nanoTime ();
140
+ endNanos = 0 ;
143
141
}
144
142
145
143
private void stopping () {
146
- endNanos = currentNanoTime ();
144
+ endNanos = clock . nanoTime ();
147
145
}
148
146
149
- private long currentNanoTime ( ) {
150
- return System . nanoTime ( );
147
+ public final Statement apply ( Statement base , Description description ) {
148
+ return new InternalWatcher (). apply ( base , description );
151
149
}
152
150
153
- @ Override final protected void succeeded (Description description ) {
154
- stopping ();
155
- succeeded (getNanos (), description );
156
- }
151
+ private class InternalWatcher extends TestWatcher {
157
152
158
- @ Override final protected void failed (Throwable e , Description description ) {
159
- stopping ();
160
- failed (getNanos (), e , description );
161
- }
153
+ @ Override protected void starting (Description description ) {
154
+ Stopwatch .this .starting ();
155
+ }
162
156
163
- @ Override final protected void skipped (AssumptionViolatedException e , Description description ) {
164
- stopping ();
165
- skipped (getNanos (), e , description );
166
- }
157
+ @ Override protected void finished (Description description ) {
158
+ Stopwatch .this .finished (getNanos (), description );
159
+ }
160
+
161
+ @ Override protected void succeeded (Description description ) {
162
+ Stopwatch .this .stopping ();
163
+ Stopwatch .this .succeeded (getNanos (), description );
164
+ }
167
165
168
- @ Override final protected void starting (Description description ) {
169
- starting ();
166
+ @ Override protected void failed (Throwable e , Description description ) {
167
+ Stopwatch .this .stopping ();
168
+ Stopwatch .this .failed (getNanos (), e , description );
169
+ }
170
+
171
+ @ Override protected void skipped (AssumptionViolatedException e , Description description ) {
172
+ Stopwatch .this .stopping ();
173
+ Stopwatch .this .skipped (getNanos (), e , description );
174
+ }
170
175
}
171
176
172
- @ Override final protected void finished (Description description ) {
173
- finished (getNanos (), description );
177
+ static class Clock {
178
+
179
+ public long nanoTime () {
180
+ return System .nanoTime ();
181
+ }
174
182
}
175
183
}
0 commit comments