Skip to content

Commit

Permalink
Refactor ExternalResourceSupport
Browse files Browse the repository at this point in the history
Refactor ExternalResourceSupport to prepare for rule-annotated methods
and other TestRules

#433
  • Loading branch information
Matthias Merdes authored and marcphilipp committed Nov 25, 2016
1 parent 8d6032b commit 184230f
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.junit.jupiter.engine.vintage.rulesupport;

import java.lang.reflect.Method;

import org.junit.platform.commons.util.ReflectionUtils;
import org.junit.rules.TestRule;

public abstract class AbstractTestRuleAdapter implements GenericBeforeAndAfterAdvice {

protected void executeMethod(String name, TestRule externalResource) {
try {
Method method = externalResource.getClass().getDeclaredMethod(name);
method.setAccessible(true);
ReflectionUtils.invokeMethod(method, externalResource);
}
catch (NoSuchMethodException | SecurityException e) {
// TODO: decide whether this should be logged
e.printStackTrace();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.junit.jupiter.engine.vintage.rulesupport;

import org.junit.rules.ExternalResource;

public class ExternalResourceAdapter extends AbstractTestRuleAdapter {

private final ExternalResource target;

public ExternalResourceAdapter(ExternalResource target) {
this.target = target;
}

@Override
public void before() {
super.executeMethod("before", this.target);
}

@Override
public void after() {
super.executeMethod("after", this.target);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,70 +10,60 @@

package org.junit.jupiter.engine.vintage.rulesupport;

import static java.util.stream.Collectors.*;

import java.lang.reflect.*;
import java.util.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.junit.Rule;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.TestExtensionContext;
import org.junit.platform.commons.util.ReflectionUtils;
import org.junit.rules.ExternalResource;

public class ExternalResourceSupport implements BeforeEachCallback, AfterEachCallback {

final Class<Rule> annotationType = Rule.class;
final Class<ExternalResource> ruleType = ExternalResource.class;
private final Class<Rule> annotationType = Rule.class;
private final Class<ExternalResource> ruleType = ExternalResource.class;

@Override
public void beforeEach(TestExtensionContext context) throws Exception {
// TODO: generalize to methods returning rule instances!
this.invokeNamedMethodOnRuleAnnotatedFields(context, "before");
this.invokeAppropriateMethodOnRuleAnnotatedMembers(context, GenericBeforeAndAfterAdvice::before);
}

@Override
public void afterEach(TestExtensionContext context) throws Exception {
// TODO: generalize to methods returning rule instances!
this.invokeNamedMethodOnRuleAnnotatedFields(context, "after");
this.invokeAppropriateMethodOnRuleAnnotatedMembers(context, GenericBeforeAndAfterAdvice::after);
}

private void invokeNamedMethodOnRuleAnnotatedFields(TestExtensionContext context, String name) {
Object testInstance = context.getTestInstance();
List<Field> externalResourceFields = this.findRuleAnnotatedFieldsOfTargetType(testInstance);

externalResourceFields.forEach(field -> this.invokeNamedMethodSafely(name, testInstance, field));
}
private void invokeAppropriateMethodOnRuleAnnotatedMembers(TestExtensionContext context,
Consumer<GenericBeforeAndAfterAdvice> methodCaller) {
// @formatter:off
Stream<AbstractTestRuleAdapter> ruleAdapters = this.findRuleAnnotatedFields(context)
.map(field -> new RuleAnnotatedField(context, field))
.map(annotatedField -> new ExternalResourceAdapter(annotatedField.getTestRuleInstance()));
// @formatter:on

private void invokeNamedMethodSafely(String name, Object testInstance, Field field) {
try {
invokeNamedMethod(testInstance, name, field);
}
catch (IllegalAccessException | NoSuchMethodException e) {
//TODO: decide whether this should be logged
e.printStackTrace();
}
ruleAdapters.forEach(methodCaller::accept);
}

private void invokeNamedMethod(Object testInstance, String name, Field field)
throws IllegalAccessException, NoSuchMethodException {
ExternalResource externalResource = (ExternalResource) field.get(testInstance);

Method method = externalResource.getClass().getDeclaredMethod(name);
method.setAccessible(true);
ReflectionUtils.invokeMethod(method, externalResource);
private Stream<Field> findRuleAnnotatedFields(TestExtensionContext context) {
Object testInstance = context.getTestInstance();
return findAnnotatedFields(testInstance, this.ruleType, this.annotationType);
}

//TODO: decide whether this should be promoted to ReflectionUtils
private List<Field> findRuleAnnotatedFieldsOfTargetType(Object testInstance) {
Field[] declaredFields = testInstance.getClass().getDeclaredFields();
// TODO: decide whether this should be promoted to AnnotationUtils
private static Stream<Field> findAnnotatedFields(Object instance, Class<?> fieldType,
Class<? extends Annotation> annotationType) {
Field[] declaredFields = instance.getClass().getDeclaredFields();

// @formatter:off
return Arrays.asList(declaredFields).stream()
.filter(field -> this.ruleType.isAssignableFrom(field.getType()))
.filter(field -> field.isAnnotationPresent(this.annotationType))
.collect(toList());
return Arrays.stream(declaredFields)
.filter(field -> fieldType.isAssignableFrom(field.getType()))
.filter(field -> field.isAnnotationPresent(annotationType));
// @formatter:on
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.junit.jupiter.engine.vintage.rulesupport;

public interface GenericBeforeAndAfterAdvice {

default void before() {
}

default void after() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.junit.jupiter.engine.vintage.rulesupport;

import java.lang.reflect.Field;

import org.junit.jupiter.api.extension.TestExtensionContext;
import org.junit.rules.ExternalResource;

class RuleAnnotatedField implements RuleAnnotatedMember {

private ExternalResource testRuleInstance;

RuleAnnotatedField(TestExtensionContext context, Field testRuleField) {
Object testInstance = context.getTestInstance();

try {
this.testRuleInstance = (ExternalResource) testRuleField.get(testInstance);
}
catch (IllegalAccessException e) {
// TODO: decide whether this should be logged
e.printStackTrace();
}
}

@Override
public ExternalResource getTestRuleInstance() {
return this.testRuleInstance;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.junit.jupiter.engine.vintage.rulesupport;

import org.junit.rules.ExternalResource;

interface RuleAnnotatedMember {
public ExternalResource getTestRuleInstance();
}

0 comments on commit 184230f

Please sign in to comment.