Skip to content

Commit

Permalink
Using reflection to get the arguments of a JUnit 5 ParameterizedTest. F…
Browse files Browse the repository at this point in the history
…ixes #372
  • Loading branch information
Jan Schäfer committed Oct 28, 2018
1 parent 727f9c5 commit f82dcd4
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,17 @@ public Object apply( Field field ) {
};
}

public static Object getFieldValueOrNull(String fieldName, Object target, String errorDescription) {
try {
Field field = target.getClass().getDeclaredField(fieldName);
return getFieldValueOrNull(field, target, errorDescription);
} catch (Exception e) {
log.warn(
format( "Not able to access field '%s'." + errorDescription, fieldName ), e );
return null;
}
}

public static Object getFieldValueOrNull(Field field, Object target, String errorDescription) {
makeAccessible( field, "" );
try {
Expand Down
7 changes: 4 additions & 3 deletions jgiven-junit5/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ test {
dependencies {
compile project(':jgiven-core')

compileOnly 'org.junit.jupiter:junit-jupiter-api:5.2.0'
compileOnly 'org.junit.jupiter:junit-jupiter-api:5.3.1'

testCompile project(':jgiven-html5-report')
testCompile 'org.junit.jupiter:junit-jupiter-engine:5.2.0'
testCompile 'org.junit.platform:junit-platform-runner:1.2.0'
testCompile 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
testCompile 'org.junit.platform:junit-platform-runner:1.3.1'
testCompile 'org.junit.jupiter:junit-jupiter-params:5.3.1'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.tngtech.jgiven.junit5;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tngtech.jgiven.impl.util.ParameterNameUtil;
import com.tngtech.jgiven.impl.util.ReflectionUtil;
import com.tngtech.jgiven.report.model.NamedArgument;

class ArgumentReflectionUtil {
private static final Logger log = LoggerFactory.getLogger( ArgumentReflectionUtil.class );

static final String METHOD_EXTENSION_CONTEXT = "org.junit.jupiter.engine.descriptor.MethodExtensionContext";
static final String TEST_TEMPLATE_INVOCATION_TEST_DESCRIPTOR = "org.junit.jupiter.engine.descriptor.TestTemplateInvocationTestDescriptor";
static final String PARAMETERIZED_TEST_INVOCATION_CONTEXT = "org.junit.jupiter.params.ParameterizedTestInvocationContext";

static final String ERROR = "Not able to access field containing test method arguments. " +
"Probably the internal representation has changed. Consider writing a bug report.";

/**
* This is a very ugly workaround to get the method arguments from the JUnit 5 context via reflection.
*/
static List<NamedArgument> getNamedArgs( ExtensionContext context ) {
List<NamedArgument> namedArgs = new ArrayList<>();

if( context.getTestMethod().get().getParameterCount() > 0 ) {
try {
if( context.getClass().getCanonicalName().equals( METHOD_EXTENSION_CONTEXT ) ) {
Field field = context.getClass().getSuperclass().getDeclaredField( "testDescriptor" );
Object testDescriptor = ReflectionUtil.getFieldValueOrNull( field, context, ERROR );
if( testDescriptor != null
&& testDescriptor.getClass().getCanonicalName().equals( TEST_TEMPLATE_INVOCATION_TEST_DESCRIPTOR ) ) {
Object invocationContext = ReflectionUtil.getFieldValueOrNull( "invocationContext", testDescriptor, ERROR );
if( invocationContext != null
&& invocationContext.getClass().getCanonicalName().equals( PARAMETERIZED_TEST_INVOCATION_CONTEXT ) ) {
Object arguments = ReflectionUtil.getFieldValueOrNull( "arguments", invocationContext, ERROR );
List<Object> args = Arrays.asList( (Object[]) arguments );
namedArgs = ParameterNameUtil.mapArgumentsWithParameterNames( context.getTestMethod().get(), args );
}
}
}
} catch( Exception e ) {
log.warn( ERROR, e );
}
}

return namedArgs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import static com.tngtech.jgiven.report.model.ExecutionStatus.FAILED;
import static com.tngtech.jgiven.report.model.ExecutionStatus.SUCCESS;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Tag;
Expand All @@ -17,7 +15,6 @@
import com.tngtech.jgiven.impl.ScenarioBase;
import com.tngtech.jgiven.impl.ScenarioHolder;
import com.tngtech.jgiven.report.impl.CommonReportHelper;
import com.tngtech.jgiven.report.model.NamedArgument;
import com.tngtech.jgiven.report.model.ReportModel;

/**
Expand Down Expand Up @@ -70,9 +67,8 @@ public void afterAll( ExtensionContext context ) throws Exception {

@Override
public void beforeEach( ExtensionContext context ) throws Exception {
List<NamedArgument> args = new ArrayList<NamedArgument>();
getScenario().startScenario( context.getTestClass().get(), context.getTestMethod().get(), args );

getScenario().startScenario( context.getTestClass().get(), context.getTestMethod().get(),
ArgumentReflectionUtil.getNamedArgs(context) );
}

@Override
Expand Down Expand Up @@ -119,4 +115,5 @@ public void postProcessTestInstance( Object testInstance, ExtensionContext conte
scenario.getExecutor().injectStages( testInstance );
scenario.getExecutor().readScenarioState( testInstance );
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.tngtech.jgiven.junit5.test;

import static org.assertj.core.api.Java6Assertions.assertThat;

import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import com.tngtech.jgiven.annotation.CaseAs;
import com.tngtech.jgiven.junit5.JGivenExtension;
import com.tngtech.jgiven.junit5.ScenarioTest;

@ExtendWith( JGivenExtension.class )
public class ParameterizedTestTest extends ScenarioTest<GivenStage, WhenStage, ThenStage> {

@ParameterizedTest( name = "{index} [{arguments}] param name" )
@ValueSource( strings = { "Hello", "World" } )
@CaseAs( "Case $1" )
public void parameterized_scenario( String param ) {
given().some_state();
when().some_action_with_a_parameter( param );
then().some_outcome();

assertThat( getScenario().getScenarioCaseModel().getDescription() ).isIn( "Case Hello", "Case World" );
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ void some_action() {
someResult = "Some Result";
}

void some_action_with_a_parameter(String s) {
someResult = "s";
}

public WhenStage some_failing_step() {
Assertions.assertTrue(false, "Intentionally failing");
return this;
Expand Down

0 comments on commit f82dcd4

Please sign in to comment.