Skip to content

Commit 066e1d6

Browse files
committed
@BeforeParam/@AfterParam for Parameterized runner
1 parent 26d6145 commit 066e1d6

File tree

3 files changed

+200
-3
lines changed

3 files changed

+200
-3
lines changed

src/main/java/org/junit/runners/Parameterized.java

+42
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.junit.runners;
22

3+
import java.lang.annotation.Annotation;
34
import java.lang.annotation.ElementType;
45
import java.lang.annotation.Inherited;
56
import java.lang.annotation.Retention;
@@ -234,13 +235,54 @@ public class Parameterized extends Suite {
234235
Class<? extends ParametersRunnerFactory> value() default BlockJUnit4ClassRunnerWithParametersFactory.class;
235236
}
236237

238+
/**
239+
* Annotation for {@code public static void} methods which should be executed before
240+
* evaluating tests with a particular parameter.
241+
*
242+
* @see org.junit.BeforeClass
243+
* @see org.junit.Before
244+
* @since 4.13
245+
*/
246+
@Retention(RetentionPolicy.RUNTIME)
247+
@Target(ElementType.METHOD)
248+
public @interface BeforeParam {
249+
}
250+
251+
/**
252+
* Annotation for {@code public static void} methods which should be executed after
253+
* evaluating tests with a particular parameter.
254+
*
255+
* @see org.junit.AfterClass
256+
* @see org.junit.After
257+
* @since 4.13
258+
*/
259+
@Retention(RetentionPolicy.RUNTIME)
260+
@Target(ElementType.METHOD)
261+
public @interface AfterParam {
262+
}
263+
237264
/**
238265
* Only called reflectively. Do not use programmatically.
239266
*/
240267
public Parameterized(Class<?> klass) throws Throwable {
241268
super(klass, RunnersFactory.createRunnersForClass(klass));
242269
}
243270

271+
@Override
272+
protected void collectInitializationErrors(List<Throwable> errors) {
273+
super.collectInitializationErrors(errors);
274+
validatePublicStaticVoidMethods(Parameterized.BeforeParam.class, errors);
275+
validatePublicStaticVoidMethods(Parameterized.AfterParam.class, errors);
276+
}
277+
278+
private void validatePublicStaticVoidMethods(Class<? extends Annotation> annotation,
279+
List<Throwable> errors) {
280+
final List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation);
281+
for (FrameworkMethod eachTestMethod : methods) {
282+
eachTestMethod.validatePublicVoid(true, errors);
283+
}
284+
}
285+
244286
private static class RunnersFactory {
245287
private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory();
246288

src/main/java/org/junit/runners/parameterized/BlockJUnit4ClassRunnerWithParameters.java

+69-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22

33
import java.lang.annotation.Annotation;
44
import java.lang.reflect.Field;
5+
import java.util.ArrayList;
56
import java.util.List;
67

78
import org.junit.runner.RunWith;
89
import org.junit.runner.notification.RunNotifier;
910
import org.junit.runners.BlockJUnit4ClassRunner;
11+
import org.junit.runners.Parameterized;
1012
import org.junit.runners.Parameterized.Parameter;
1113
import org.junit.runners.model.FrameworkField;
1214
import org.junit.runners.model.FrameworkMethod;
1315
import org.junit.runners.model.InitializationError;
16+
import org.junit.runners.model.MultipleFailureException;
1417
import org.junit.runners.model.Statement;
1518

1619
/**
@@ -134,8 +137,72 @@ protected void validateFields(List<Throwable> errors) {
134137
}
135138

136139
@Override
137-
protected Statement classBlock(RunNotifier notifier) {
138-
return childrenInvoker(notifier);
140+
protected Statement classBlock(final RunNotifier notifier) {
141+
Statement statement = childrenInvoker(notifier);
142+
statement = withBeforeParams(statement);
143+
statement = withAfterParams(statement);
144+
return statement;
145+
}
146+
147+
private Statement withBeforeParams(Statement statement) {
148+
final List<FrameworkMethod> befores = getTestClass()
149+
.getAnnotatedMethods(Parameterized.BeforeParam.class);
150+
return befores.isEmpty() ? statement : new RunBeforeParams(statement, befores);
151+
}
152+
153+
private class RunBeforeParams extends Statement {
154+
private final Statement next;
155+
private final List<FrameworkMethod> befores;
156+
157+
RunBeforeParams(Statement next, List<FrameworkMethod> befores) {
158+
this.next = next;
159+
this.befores = befores;
160+
}
161+
162+
@Override
163+
public void evaluate() throws Throwable {
164+
for (FrameworkMethod before : befores) {
165+
final int paramCount = before.getMethod().getParameterTypes().length;
166+
before.invokeExplosively(null, paramCount == 0 ? (Object[]) null : parameters);
167+
}
168+
next.evaluate();
169+
}
170+
}
171+
172+
private Statement withAfterParams(Statement statement) {
173+
final List<FrameworkMethod> afters = getTestClass()
174+
.getAnnotatedMethods(Parameterized.AfterParam.class);
175+
return afters.isEmpty() ? statement : new RunAfterParams(statement, afters);
176+
}
177+
178+
private class RunAfterParams extends Statement {
179+
private final Statement next;
180+
private final List<FrameworkMethod> afters;
181+
182+
RunAfterParams(Statement next, List<FrameworkMethod> afters) {
183+
this.next = next;
184+
this.afters = afters;
185+
}
186+
187+
@Override
188+
public void evaluate() throws Throwable {
189+
final List<Throwable> errors = new ArrayList<Throwable>();
190+
try {
191+
next.evaluate();
192+
} catch (Throwable e) {
193+
errors.add(e);
194+
} finally {
195+
for (FrameworkMethod each : afters) {
196+
try {
197+
final int paramCount = each.getMethod().getParameterTypes().length;
198+
each.invokeExplosively(null, paramCount == 0 ? (Object[]) null : parameters);
199+
} catch (Throwable e) {
200+
errors.add(e);
201+
}
202+
}
203+
}
204+
MultipleFailureException.assertEmpty(errors);
205+
}
139206
}
140207

141208
@Override

src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java

+89-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import static java.util.Arrays.asList;
44
import static org.hamcrest.CoreMatchers.allOf;
55
import static org.hamcrest.CoreMatchers.containsString;
6+
import static org.hamcrest.MatcherAssert.assertThat;
67
import static org.junit.Assert.assertEquals;
7-
import static org.junit.Assert.assertThat;
88
import static org.junit.Assert.assertTrue;
99
import static org.junit.Assert.fail;
1010
import static org.junit.experimental.results.PrintableResult.testResult;
@@ -16,6 +16,7 @@
1616

1717
import org.junit.AfterClass;
1818
import org.junit.BeforeClass;
19+
import org.junit.FixMethodOrder;
1920
import org.junit.Test;
2021
import org.junit.runner.Description;
2122
import org.junit.runner.JUnitCore;
@@ -24,6 +25,7 @@
2425
import org.junit.runner.RunWith;
2526
import org.junit.runner.Runner;
2627
import org.junit.runner.notification.Failure;
28+
import org.junit.runners.MethodSorters;
2729
import org.junit.runners.Parameterized;
2830
import org.junit.runners.Parameterized.Parameter;
2931
import org.junit.runners.Parameterized.Parameters;
@@ -259,6 +261,92 @@ public void beforeAndAfterClassAreRun() {
259261
assertEquals("before after ", fLog);
260262
}
261263

264+
@RunWith(Parameterized.class)
265+
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
266+
public static class BeforeParamAndAfterParam {
267+
@BeforeClass
268+
public static void before() {
269+
fLog += "beforeClass ";
270+
}
271+
272+
@Parameterized.BeforeParam
273+
public static void beforeParam(String x) {
274+
fLog += "before(" + x + ") ";
275+
}
276+
277+
@Parameterized.AfterParam
278+
public static void afterParam() {
279+
fLog += "afterParam ";
280+
}
281+
282+
@AfterClass
283+
public static void after() {
284+
fLog += "afterClass ";
285+
}
286+
287+
private final String x;
288+
289+
public BeforeParamAndAfterParam(String x) {
290+
this.x = x;
291+
}
292+
293+
@Parameters
294+
public static Collection<String> data() {
295+
return Arrays.asList("A", "B");
296+
}
297+
298+
@Test
299+
public void first() {
300+
fLog += "first(" + x + ") ";
301+
}
302+
303+
@Test
304+
public void second() {
305+
fLog += "second(" + x + ") ";
306+
}
307+
}
308+
309+
@Test
310+
public void beforeParamAndAfterParamAreRun() {
311+
fLog = "";
312+
final Result result = JUnitCore.runClasses(BeforeParamAndAfterParam.class);
313+
assertEquals(0, result.getFailureCount());
314+
assertEquals("beforeClass before(A) first(A) second(A) afterParam "
315+
+ "before(B) first(B) second(B) afterParam afterClass ", fLog);
316+
}
317+
318+
@RunWith(Parameterized.class)
319+
public static class BeforeParamAndAfterParamError {
320+
@Parameterized.BeforeParam
321+
public void beforeParam(String x) {
322+
}
323+
324+
@Parameterized.AfterParam
325+
private static void afterParam() {
326+
}
327+
328+
public BeforeParamAndAfterParamError(String x) {
329+
}
330+
331+
@Parameters
332+
public static Collection<String> data() {
333+
return Arrays.asList("A", "B");
334+
}
335+
336+
@Test
337+
public void test() {
338+
}
339+
}
340+
341+
@Test
342+
public void beforeParamAndAfterParamValidation() {
343+
fLog = "";
344+
final Result result = JUnitCore.runClasses(BeforeParamAndAfterParamError.class);
345+
assertEquals(1, result.getFailureCount());
346+
assertThat(result.getFailures().get(0).getMessage(), containsString("beforeParam() should be static"));
347+
assertThat(result.getFailures().get(0).getMessage(), containsString("afterParam() should be public"));
348+
}
349+
262350
@RunWith(Parameterized.class)
263351
static public class EmptyTest {
264352
@BeforeClass

0 commit comments

Comments
 (0)