Created
March 12, 2012 09:08
-
-
Save keerts/2020820 to your computer and use it in GitHub Desktop.
Flexible methods in JUnit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package nl.avisi.langur.test; | |
import java.io.InputStream; | |
import java.io.InputStreamReader; | |
import java.io.Reader; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Method; | |
import java.util.List; | |
import org.apache.commons.io.IOUtils; | |
import org.junit.Test; | |
import org.junit.runners.BlockJUnit4ClassRunner; | |
import org.junit.runners.model.FrameworkMethod; | |
import org.junit.runners.model.InitializationError; | |
import org.junit.runners.model.Statement; | |
import org.springframework.core.io.DefaultResourceLoader; | |
import org.springframework.core.io.Resource; | |
public class InputProvidingRunner extends BlockJUnit4ClassRunner { | |
public InputProvidingRunner(Class<?> klass) throws InitializationError { | |
super(klass); | |
} | |
@Override | |
protected void validateTestMethods(List<Throwable> errors) { | |
validatePublicVoidAndSuitableMethodsArgs(Test.class, false, errors); | |
} | |
protected void validatePublicVoidAndSuitableMethodsArgs(Class<? extends Annotation> annotation, boolean isStatic, List<Throwable> errors) { | |
List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation); | |
for (FrameworkMethod eachTestMethod : methods) | |
validatePublicVoidAndSuitableMethodArgs(eachTestMethod, isStatic, errors); | |
} | |
public void validatePublicVoidAndSuitableMethodArgs(FrameworkMethod testMethod, boolean isStatic, List<Throwable> errors) { | |
testMethod.validatePublicVoid(isStatic, errors); | |
validateSuitableMethodArgs(testMethod, errors); | |
} | |
public void validateSuitableMethodArgs(FrameworkMethod fMethod, List<Throwable> errors) { | |
Method javaMethod = fMethod.getMethod(); | |
Annotation[][] parameterAnnotations = javaMethod.getParameterAnnotations(); | |
for (Annotation[] annotations : parameterAnnotations) { | |
if (annotations.length != 1) { | |
errors.add(new Exception("Method " + fMethod.getName() + " should have exactly 1 annotation")); | |
} | |
if (annotations[0].annotationType() != TestInput.class) { | |
errors.add(new Exception("Method " + fMethod.getName() + " parameters can only be annotated with @Testinput")); | |
} | |
} | |
} | |
@Override | |
protected Statement methodInvoker(final FrameworkMethod fMethod, final Object test) { | |
Method javaMethod = fMethod.getMethod(); | |
Annotation[][] parameterAnnotations = javaMethod.getParameterAnnotations(); | |
final Object[] params = new Object[parameterAnnotations.length]; | |
for (int i = 0; i < params.length; i++) { | |
Annotation[] annotations = parameterAnnotations[i]; | |
TestInput testInput = (TestInput) annotations[0]; | |
String location = testInput.value(); | |
Class<?> parameterType = javaMethod.getParameterTypes()[i]; | |
params[i] = injectResource(location, parameterType); | |
} | |
return new Statement() { | |
@Override | |
public void evaluate() throws Throwable { | |
fMethod.invokeExplosively(test, params); | |
} | |
}; | |
} | |
private Object injectResource(String location, Class<?> parameterType) { | |
Resource resource; | |
try { | |
// spring dependency, with a bit of work, you can easily get around it | |
resource = new DefaultResourceLoader().getResource(location); | |
if (parameterType == InputStream.class) { | |
return resource.getInputStream(); | |
} else if (parameterType == Reader.class) { | |
return new InputStreamReader(resource.getInputStream()); | |
} else if (parameterType == String.class) { | |
// commons.io dependency. If you want, you can easily get rid of this dependency | |
return IOUtils.toString(resource.getInputStream()); | |
} | |
} catch (Exception e) { | |
throw new TestInputNotFoundException(e); | |
} | |
throw new TestInputNotFoundException("unsupported resource type, use one of [Reader, InputStream, String]"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package nl.avisi.langur.test; | |
import static java.lang.annotation.RetentionPolicy.*; | |
import java.lang.annotation.ElementType; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.Target; | |
@Target(value = { ElementType.PARAMETER }) | |
@Retention(RUNTIME) | |
public @interface TestInput { | |
String value(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package nl.avisi.langur.test; | |
public class TestInputNotFoundException extends RuntimeException { | |
private static final long serialVersionUID = 1L; | |
public TestInputNotFoundException(Exception e) { | |
super(e); | |
} | |
public TestInputNotFoundException(String message) { | |
super(message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment