package stepdef.subtest; import static org.junit.Assert.assertTrue; import org.apache.commons.lang3.ArrayUtils; import com.github.shell88.bddvideoannotator.javaadapters.CucumberReportingAdapter; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.List; /** * Represents a Cucumber-JVM-testrun that will be started in an own thread. It * will use an instance of * {@link com.github.shell88.bddvideoannotator.javaadapters.CucumberReportingAdapter} * that is specified in the constructor. So this class enables mocking of * {@link com.github.shell88.bddvideoannotator.javaadapters.CucumberReportingAdapter} * in a Cucumber-JVM-testrun. * * @author Hell * */ public class CucumberSubTestThreadWithAdapterInstance extends Thread { private final String pathOfTestProxyClass = stepdef.subtest.CucumberReportingAdapterTestProxy.class.getCanonicalName(); private CucumberReportingAdapter mockedAdapter; private File dirContents; private ExceptionCollector exceptionCollector; /** * @param mockedAdapter * - the instance that should be used for the testrun * @param dirContents * - The directory containing the feature file(s) and the * stepdefinitions. Feature-files must be located in dirContents, for * the glue-Path the stepdefinition-Classes must be located in a * package named like dirContents Example: +dir_content *test.feature * *dir_content - StepDef.class */ public CucumberSubTestThreadWithAdapterInstance( CucumberReportingAdapter mockedAdapter, File dirContents) { this.mockedAdapter = mockedAdapter; this.dirContents = dirContents; exceptionCollector = new ExceptionCollector(); this.setUncaughtExceptionHandler(exceptionCollector); } public List<Throwable> getThrownExceptions() { return this.exceptionCollector.getThrownExceptions(); } @Override public void run() { // For better orientation System.out.println("--STARTING SUBTEST IN " + this.dirContents.getAbsolutePath()); CucumberReportingAdapterTestProxy.setUnderlyingInstance(mockedAdapter); String[] argsCucumber = new String[] { dirContents.getAbsolutePath(), "--glue", dirContents.getName(), "-p", pathOfTestProxyClass }; //Stepdefinition must be detectable by Cucumber-JVM URL[] urlstoLoad = ((URLClassLoader) (ClassLoader.getSystemClassLoader())) .getURLs(); try { urlstoLoad = ArrayUtils.add(urlstoLoad, dirContents.getAbsoluteFile() .toURI().toURL()); } catch (MalformedURLException e1) { this.getUncaughtExceptionHandler().uncaughtException(this, e1); return; } URLClassLoader classLoader = new URLClassLoader(urlstoLoad); this.setContextClassLoader(classLoader); byte retValue = 1; try { //CucumberJVM will alway use Class Loader of current thread, and not that one //specified in run Method (see https://github.com/cucumber/cucumber-jvm/issues/880) retValue = cucumber.api.cli.Main.run(argsCucumber, Thread.currentThread().getContextClassLoader()); } catch (IOException e) { this.getUncaughtExceptionHandler().uncaughtException(this, e); return; } assertTrue("Return Code of Cucumber-Thread != 0", retValue == 0); System.out.println("---END OF SUBTEST"); } }