Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Example of how to use parameterized tests with Arquillian. Supports running arquillian tests both "in client" or "in container". For more information see: http://poolik.com/2014/02/how-to-run-parameterized-junit-arquillian-tests/
public class ArquillianUtils {
public static boolean isRunningInContainer() {
try {
new InitialContext().lookup("java:comp/env");
return true;
} catch (NamingException e) {
return false;
}
}
}
@RunWith(Arquillian.class)
public class GzipArquillianTest {
public static final List<String> GZIP_RESOURCES = Arrays.asList(
"style.css", "index.html", "index.xhtml", "index.js", "index.main.dart", "js/index2.js");
@Rule
public ParameterRule<String> rule = new ParameterRule<>(GZIP_RESOURCES);
@Deployment(testable = false)
public static WebArchive create() {
WebArchive archive = ShrinkWrap
.create(WebArchive.class, GzipArquillianTest.class.getSimpleName() + ".war")
.addClasses(ParameterRule.class, ArquillianUtils.class, Parameter.class);
for (String resource : GZIP_RESOURCES) {
archive.addAsWebResource(EmptyAsset.INSTANCE, resource);
}
return archive.addPackage(GZipServletFilter.class.getPackage());
}
private @Parameter String resource;
private @ArquillianResource URL base;
@Test
public void testResourceGzipped() throws IOException {
URLConnection connection = new URL(base, resource).openConnection();
connection.setRequestProperty("Accept-Encoding", "gzip");
try (InputStream inputStrem = connection.getInputStream()) {
assertThat(connection.getContentEncoding(), is("gzip"));
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Parameter {
}
public class ParameterRule<T> implements MethodRule {
private final List<T> params;
public ParameterRule(List<T> params) {
if (params == null || params.size() == 0) {
throw new IllegalArgumentException("'params' must be specified and have more then zero length!");
}
this.params = params;
}
@Override
public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
boolean runInContainer = getDeploymentMethod(target).getAnnotation(Deployment.class).testable();
if (runInContainer) {
evaluateParametersInContainer(base, target);
} else {
evaluateParametersInClient(base, target);
}
}
};
}
private Method getDeploymentMethod(Object target) throws NoSuchMethodException {
Method[] methods = target.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.getAnnotation(Deployment.class) != null) return method;
}
throw new IllegalStateException("No method with @Deployment annotation found!");
}
private void evaluateParametersInContainer(Statement base, Object target) throws Throwable {
if (ArquillianUtils.isRunningInContainer()) {
evaluateParamsToTarget(base, target);
} else {
ignoreStatementExecution(base);
}
}
private void evaluateParametersInClient(Statement base, Object target) throws Throwable {
if (ArquillianUtils.isRunningInContainer()) {
ignoreStatementExecution(base);
} else {
evaluateParamsToTarget(base, target);
}
}
private void evaluateParamsToTarget(Statement base, Object target) throws Throwable {
for (Object param : params) {
Field targetField = getTargetField(target);
if (!targetField.isAccessible()) {
targetField.setAccessible(true);
}
targetField.set(target, param);
base.evaluate();
}
}
private Field getTargetField(Object target) throws NoSuchFieldException {
Field[] allFields = target.getClass().getDeclaredFields();
for (Field field : allFields) {
if (field.getAnnotation(Parameter.class) != null) return field;
}
throw new IllegalStateException("No field with @Parameter annotation found! Forgot to add it?");
}
private void ignoreStatementExecution(Statement base) {
try {
base.evaluate();
} catch (Throwable ignored) {}
}
}

urbandroid commented Jul 17, 2017 edited

this gist solves the problem i mentioned in https://gist.github.com/aslakknutsen/1358803 but it has some design issues.

if i want to add two separate parameters with two rules looks like it is not possible.
only way to achieve two separate parameters such like actual and expected i will have to create new helper class use as type parameter just for test purposes which composed with my mentioned classes which is cumbersome when you think, a new class going to be needed it for every single pair of actual and expected type.

it has dependency to arquillian which makes this rule unusable for other scenarios.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment