diff --git a/build.gradle b/build.gradle index 1f3bfb1..29c7367 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: 'io.codearte.nexus-staging' ext { - targetSdkVersion = 27 + targetSdkVersion = 28 buildToolsVersion = '28.0.3' minSdkVersion = '14' diff --git a/cucumber-android/build.gradle b/cucumber-android/build.gradle index 3eb3ab1..fc98926 100644 --- a/cucumber-android/build.gradle +++ b/cucumber-android/build.gradle @@ -14,7 +14,7 @@ configurations.all { dependencies { api "io.cucumber:cucumber-java:$cucumber_javaVersion" api 'junit:junit:4.12' - api 'com.android.support.test:runner:1.0.2' + api "androidx.test:runner:1.1.1" testImplementation "org.robolectric:robolectric:4.1" testImplementation "org.powermock:powermock-api-mockito2:2.0.0" testImplementation "org.powermock:powermock-module-junit4:2.0.0" diff --git a/cucumber-android/src/main/java/cucumber/api/android/CucumberAndroidJUnitRunner.java b/cucumber-android/src/main/java/cucumber/api/android/CucumberAndroidJUnitRunner.java index 0394f38..400b9b0 100644 --- a/cucumber-android/src/main/java/cucumber/api/android/CucumberAndroidJUnitRunner.java +++ b/cucumber-android/src/main/java/cucumber/api/android/CucumberAndroidJUnitRunner.java @@ -1,11 +1,7 @@ package cucumber.api.android; import android.os.Bundle; -import android.support.test.runner.AndroidJUnitRunner; - -import java.io.File; - -import cucumber.api.CucumberOptions; +import androidx.test.runner.AndroidJUnitRunner; import cucumber.runtime.android.CucumberJUnitRunnerBuilder; /** @@ -19,39 +15,15 @@ public class CucumberAndroidJUnitRunner extends AndroidJUnitRunner { @Override public void onCreate(final Bundle bundle) { - bundle.putString("plugin", getPluginConfigurationString()); // we programmatically create the plugin configuration bundle.putString(ARGUMENT_ORCHESTRATOR_RUNNER_BUILDER, CucumberJUnitRunnerBuilder.class.getName()); + //there is no need to scan all classes - we can fake this execution to be for single class + //because we delegate test execution to CucumberJUnitRunner + bundle.putString("class", CucumberJUnitRunnerBuilder.class.getName()); arguments = bundle; super.onCreate(bundle); } - /** - * Since we want to checkout the external storage directory programmatically, we create the plugin configuration - * here, instead of the {@link CucumberOptions} annotation. - * - * @return the plugin string for the configuration, which contains XML, HTML and JSON paths - */ - private String getPluginConfigurationString() { - final String cucumber = "cucumber"; - final String separator = "--"; - return - "junit:" + getAbsoluteFilesPath() + "/" + cucumber + ".xml" + separator + - "html:" + getAbsoluteFilesPath() + "/" + cucumber + ".html" + separator + - "json:" + getAbsoluteFilesPath() + "/" + cucumber + ".json"; - } - - /** - * The path which is used for the report files. - * - * @return the absolute path for the report files - */ - private String getAbsoluteFilesPath() { - //sdcard/Android/data/cucumber.cukeulator - File directory = getTargetContext().getExternalFilesDir(null); - return new File(directory,"reports").getAbsolutePath(); - } - public Bundle getArguments() { return arguments; } diff --git a/cucumber-android/src/main/java/cucumber/runtime/android/AndroidObjectFactory.java b/cucumber-android/src/main/java/cucumber/runtime/android/AndroidObjectFactory.java deleted file mode 100644 index feec4d2..0000000 --- a/cucumber-android/src/main/java/cucumber/runtime/android/AndroidObjectFactory.java +++ /dev/null @@ -1,76 +0,0 @@ -package cucumber.runtime.android; - -import android.app.Instrumentation; -import android.content.Intent; -import android.test.ActivityInstrumentationTestCase2; -import android.test.AndroidTestCase; -import android.test.InstrumentationTestCase; -import cucumber.api.java.ObjectFactory; - -/** - * Android specific implementation of {@link ObjectFactory} which will - * make sure that created test classes have all necessary references to the executing {@link android.app.Instrumentation} - * and the associated {@link android.content.Context}. - */ -@SuppressWarnings("deprecation") -final class AndroidObjectFactory implements ObjectFactory { - - /** - * The actual {@link ObjectFactory} responsible for creating instances. - */ - private final ObjectFactory delegate; - - /** - * The instrumentation to set to the objects. - */ - private final Instrumentation instrumentation; - - /** - * Creates a new instance using the given delegate {@link ObjectFactory} to - * forward all calls to and using the given {@link android.app.Instrumentation} to set to the instantiated - * android test classes. - * - * @param delegate the {@link ObjectFactory} to delegate to - * @param instrumentation the {@link android.app.Instrumentation} to set to the tests - */ - AndroidObjectFactory(final ObjectFactory delegate, final Instrumentation instrumentation) { - this.delegate = delegate; - this.instrumentation = instrumentation; - } - - @Override - public void start() { - delegate.start(); - } - - @Override - public void stop() { - delegate.stop(); - } - - @Override - public boolean addClass(final Class clazz) { - return delegate.addClass(clazz); - } - - @Override - public T getInstance(final Class type) { - T instance = delegate.getInstance(type); - decorate(instance); - return instance; - } - - private void decorate(final Object instance) { - if (instance instanceof ActivityInstrumentationTestCase2) { - final ActivityInstrumentationTestCase2 activityInstrumentationTestCase2 = (ActivityInstrumentationTestCase2) instance; - activityInstrumentationTestCase2.injectInstrumentation(instrumentation); - final Intent intent = new Intent(); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - activityInstrumentationTestCase2.setActivityIntent(intent); - } else if (instance instanceof InstrumentationTestCase) { - ((InstrumentationTestCase) instance).injectInstrumentation(instrumentation); - } else if (instance instanceof AndroidTestCase) { - ((AndroidTestCase) instance).setContext(instrumentation.getTargetContext()); - } - } -} diff --git a/cucumber-android/src/main/java/cucumber/runtime/android/CucumberExecutor.java b/cucumber-android/src/main/java/cucumber/runtime/android/CucumberExecutor.java index 4d12055..e788003 100644 --- a/cucumber-android/src/main/java/cucumber/runtime/android/CucumberExecutor.java +++ b/cucumber-android/src/main/java/cucumber/runtime/android/CucumberExecutor.java @@ -192,11 +192,10 @@ private BackendSupplier createBackends() { public Collection get() { final Reflections reflections = new Reflections(classFinder); final ObjectFactory delegateObjectFactory = ObjectFactoryLoader.loadObjectFactory(classFinder, Env.INSTANCE.get(ObjectFactory.class.getName())); - final AndroidObjectFactory objectFactory = new AndroidObjectFactory(delegateObjectFactory, instrumentation); final TypeRegistryConfigurer typeRegistryConfigurer = reflections.instantiateExactlyOneSubclass(TypeRegistryConfigurer.class, MultiLoader.packageName(runtimeOptions.getGlue()), new Class[0], new Object[0], new DefaultTypeRegistryConfiguration()); final TypeRegistry typeRegistry = new TypeRegistry(typeRegistryConfigurer.locale()); typeRegistryConfigurer.configureTypeRegistry(typeRegistry); - return singletonList(new JavaBackend(objectFactory, classFinder, typeRegistry)); + return singletonList(new JavaBackend(delegateObjectFactory, classFinder, typeRegistry)); } }; diff --git a/cucumber-android/src/main/java/cucumber/runtime/android/CucumberJUnitRunner.java b/cucumber-android/src/main/java/cucumber/runtime/android/CucumberJUnitRunner.java index 0379669..e1e771f 100644 --- a/cucumber-android/src/main/java/cucumber/runtime/android/CucumberJUnitRunner.java +++ b/cucumber-android/src/main/java/cucumber/runtime/android/CucumberJUnitRunner.java @@ -1,38 +1,29 @@ package cucumber.runtime.android; +import androidx.test.platform.app.InstrumentationRegistry; +import cucumber.api.android.CucumberAndroidJUnitRunner; +import cucumber.runtime.formatter.UniqueTestNameProvider; +import gherkin.events.PickleEvent; import org.junit.runner.Description; -import org.junit.runner.Result; import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.Filterable; import org.junit.runner.manipulation.NoTestsRemainException; import org.junit.runner.notification.RunNotifier; -import android.support.test.InstrumentationRegistry; -import android.util.Pair; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.Set; - -import cucumber.api.android.CucumberAndroidJUnitRunner; -import cucumber.runtime.Utils; -import gherkin.events.PickleEvent; public class CucumberJUnitRunner extends Runner implements Filterable { - private final CucumberAndroidJUnitRunner instrumentationRunner; - private final CucumberExecutor cucumberExecutor; private final List pickleEvents; - public CucumberJUnitRunner(Class testClass) { - instrumentationRunner = (CucumberAndroidJUnitRunner) InstrumentationRegistry + private final UniqueTestNameProvider uniqueTestNameProvider = new UniqueTestNameProvider<>(); + + public CucumberJUnitRunner(@SuppressWarnings("unused") Class testClass) { + CucumberAndroidJUnitRunner instrumentationRunner = (CucumberAndroidJUnitRunner) InstrumentationRegistry .getInstrumentation(); cucumberExecutor = new CucumberExecutor(new Arguments(instrumentationRunner.getArguments()), instrumentationRunner); @@ -50,8 +41,8 @@ public Description getDescription() { } private Description makeDescriptionFromPickle(PickleEvent pickleEvent) { - Pair testName = calculateUniqueTestName(pickleEvent); - return Description.createTestDescription(testName.first, testName.second, testName.second); + String testName = uniqueTestNameProvider.calculateUniqueTestName(pickleEvent, pickleEvent.pickle.getName(), pickleEvent.uri); + return Description.createTestDescription(pickleEvent.uri, testName, testName); } @Override @@ -59,6 +50,7 @@ public void run(final RunNotifier notifier) { cucumberExecutor.execute(); } + @Override public int testCount() { return pickleEvents.size(); } @@ -77,54 +69,4 @@ public void filter(final Filter filter) throws NoTestsRemainException { } } - /** - * The stored unique test name for a test case. - * We use an identity hash-map since we want to distinct all test case objects. - * Thus, the key is a unique test case object.
- * The mapped value is the unique test name, which maybe differs from test case original - * non-unique name. - */ - private final Map - uniqueTestNameForTestCase = new IdentityHashMap<>(); - - /** - * The stored unique test names grouped by feature.
- * The key contains the feature file.
- * The mapped value is a set of unique test names for the feature. - */ - private final Map> uniqueTestNamesForFeature = new HashMap<>(); - - /** - * Creates a unique test name for the given test case by filling the internal maps - * {@link #uniqueTestNameForTestCase} and {@link #uniqueTestNamesForFeature}.
- * If the test case name is unique, it will be used, otherwise, a index will be added " 2", " - * 3", " 4", ... - * - * @param pickleEvent the test case - * @return a unique test name - */ - private Pair calculateUniqueTestName(PickleEvent pickleEvent) { - String existingName = uniqueTestNameForTestCase.get(pickleEvent); - if (existingName != null) { - // Nothing to do: there is already a test name for the passed test case object - return new Pair<>(pickleEvent.uri, existingName); - } - final String feature = pickleEvent.uri; - String uniqueTestCaseName = pickleEvent.pickle.getName(); - if (!uniqueTestNamesForFeature.containsKey(feature)) { - // First test case of the feature - uniqueTestNamesForFeature.put(feature, new HashSet()); - } - final Set uniqueTestNamesSetForFeature = uniqueTestNamesForFeature.get(feature); - // If "name" already exists, the next one is "name_2" or "name with spaces 2" - int i = 2; - while (uniqueTestNamesSetForFeature.contains(uniqueTestCaseName)) { - uniqueTestCaseName = Utils - .getUniqueTestNameForScenarioExample(pickleEvent.pickle.getName(), i); - i++; - } - uniqueTestNamesSetForFeature.add(uniqueTestCaseName); - uniqueTestNameForTestCase.put(pickleEvent, uniqueTestCaseName); - return new Pair<>(pickleEvent.uri, uniqueTestNameForTestCase.get(pickleEvent)); - } } diff --git a/cucumber-android/src/main/java/cucumber/runtime/android/CucumberJUnitRunnerBuilder.java b/cucumber-android/src/main/java/cucumber/runtime/android/CucumberJUnitRunnerBuilder.java index 72c5d99..2054779 100644 --- a/cucumber-android/src/main/java/cucumber/runtime/android/CucumberJUnitRunnerBuilder.java +++ b/cucumber-android/src/main/java/cucumber/runtime/android/CucumberJUnitRunnerBuilder.java @@ -5,8 +5,8 @@ public class CucumberJUnitRunnerBuilder extends RunnerBuilder { @Override - public Runner runnerForClass(final Class testClass) { - if (testClass.equals(this.getClass())) { + public Runner runnerForClass(Class testClass) { + if (testClass.equals(getClass())) { return new CucumberJUnitRunner(testClass); } diff --git a/cucumber-android/src/main/java/cucumber/runtime/formatter/AndroidInstrumentationReporter.java b/cucumber-android/src/main/java/cucumber/runtime/formatter/AndroidInstrumentationReporter.java index b3616b6..6909a0f 100644 --- a/cucumber-android/src/main/java/cucumber/runtime/formatter/AndroidInstrumentationReporter.java +++ b/cucumber-android/src/main/java/cucumber/runtime/formatter/AndroidInstrumentationReporter.java @@ -12,15 +12,9 @@ import cucumber.api.event.TestSourceRead; import cucumber.api.event.TestStepFinished; import cucumber.runtime.UndefinedStepsTracker; -import cucumber.runtime.Utils; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Set; /** * Reports the test results to the instrumentation through {@link Instrumentation#sendStatus(int, Bundle)} calls. @@ -147,6 +141,7 @@ public void receive(TestCaseFinished event) { private final UndefinedStepsTracker undefinedStepsTracker; + private final UniqueTestNameProvider uniqueTestNameProvider = new UniqueTestNameProvider<>(); /** * Creates a new instance for the given parameters @@ -181,7 +176,7 @@ void startTestCase(final TestCase testCase) { } currentTestCaseNumber++; // Since the names of test cases are not guaranteed to be unique, we must check for unique names - currentTestCaseName = calculateUniqueTestName(testCase); + currentTestCaseName = uniqueTestNameProvider.calculateUniqueTestName(testCase, testCase.getName(), testCase.getUri()); resetSeverestResult(); final Bundle testStart = createBundle(currentFeatureName, currentTestCaseName); instrumentation.sendStatus(StatusCodes.START, testStart); @@ -290,50 +285,5 @@ private static String getStackTrace(final Throwable throwable) { return stringWriter.getBuffer().toString(); } - /** - * The stored unique test name for a test case. - * We use an identity hash-map since we want to distinct all test case objects. - * Thus, the key is a unique test case object.
- * The mapped value is the unique test name, which maybe differs from test case original non-unique name. - */ - private final Map uniqueTestNameForTestCase = new IdentityHashMap(); - - /** - * The stored unique test names grouped by feature.
- * The key contains the feature file.
- * The mapped value is a set of unique test names for the feature. - */ - private final Map> uniqueTestNamesForFeature = new HashMap>(); - - /** - * Creates a unique test name for the given test case by filling the internal maps - * {@link #uniqueTestNameForTestCase} and {@link #uniqueTestNamesForFeature}.
- * If the test case name is unique, it will be used, otherwise, a index will be added " 2", " 3", " 4", ... - * @param testCase the test case - * @return a unique test name - */ - private String calculateUniqueTestName(TestCase testCase) { - String existingName = uniqueTestNameForTestCase.get(testCase); - if (existingName != null) { - // Nothing to do: there is already a test name for the passed test case object - return existingName; - } - final String feature = testCase.getUri(); - String uniqueTestCaseName = testCase.getName(); - if (!uniqueTestNamesForFeature.containsKey(feature)) { - // First test case of the feature - uniqueTestNamesForFeature.put(feature, new HashSet()); - } - final Set uniqueTestNamesSetForFeature = uniqueTestNamesForFeature.get(feature); - // If "name" already exists, the next one is "name_2" or "name with spaces 2" - int i = 2; - while (uniqueTestNamesSetForFeature.contains(uniqueTestCaseName)) { - uniqueTestCaseName = Utils.getUniqueTestNameForScenarioExample(testCase.getName(), i); - i++; - } - uniqueTestNamesSetForFeature.add(uniqueTestCaseName); - uniqueTestNameForTestCase.put(testCase, uniqueTestCaseName); - return uniqueTestNameForTestCase.get(testCase); - } } diff --git a/cucumber-android/src/main/java/cucumber/runtime/formatter/UniqueTestNameProvider.java b/cucumber-android/src/main/java/cucumber/runtime/formatter/UniqueTestNameProvider.java new file mode 100644 index 0000000..ef048ba --- /dev/null +++ b/cucumber-android/src/main/java/cucumber/runtime/formatter/UniqueTestNameProvider.java @@ -0,0 +1,58 @@ +package cucumber.runtime.formatter; + +import cucumber.runtime.Utils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +public class UniqueTestNameProvider { + + /** + * The stored unique test name for a test case. + * We use an identity hash-map since we want to distinct all test case objects. + * Thus, the key is a unique test case object.
+ * The mapped value is the unique test name, which maybe differs from test case original non-unique name. + */ + private final Map uniqueTestNameForTestCase = new IdentityHashMap<>(); + + /** + * The stored unique test names grouped by feature.
+ * The key contains the feature file.
+ * The mapped value is a set of unique test names for the feature. + */ + private final Map> uniqueTestNamesForFeature = new HashMap<>(); + + /** + * Creates a unique test name for the given test case by filling the internal maps + * {@link #uniqueTestNameForTestCase} and {@link #uniqueTestNamesForFeature}.
+ * If the test case name is unique, it will be used, otherwise, a index will be added " 2", " 3", " 4", ... + * @param testCase the test case + * @return a unique test name + */ + public String calculateUniqueTestName(T testCase,String testCaseName,String testCaseUri) { + String existingName = uniqueTestNameForTestCase.get(testCase); + if (existingName != null) { + // Nothing to do: there is already a test name for the passed test case object + return existingName; + } + String uniqueTestCaseName = testCaseName; + Set uniqueTestNamesSetForFeature = uniqueTestNamesForFeature.get(testCaseUri); + if (uniqueTestNamesSetForFeature==null) { + // First test case of the feature + uniqueTestNamesSetForFeature=new HashSet<>(); + uniqueTestNamesForFeature.put(testCaseUri, uniqueTestNamesSetForFeature); + } + // If "name" already exists, the next one is "name_2" or "name with spaces 2" + int i = 2; + while (uniqueTestNamesSetForFeature.contains(uniqueTestCaseName)) { + uniqueTestCaseName = Utils.getUniqueTestNameForScenarioExample(testCaseName, i); + i++; + } + uniqueTestNamesSetForFeature.add(uniqueTestCaseName); + uniqueTestNameForTestCase.put(testCase, uniqueTestCaseName); + return uniqueTestNameForTestCase.get(testCase); + } +} diff --git a/cucumber-android/src/test/java/cucumber/runtime/android/AndroidObjectFactoryTest.java b/cucumber-android/src/test/java/cucumber/runtime/android/AndroidObjectFactoryTest.java deleted file mode 100644 index ff4f742..0000000 --- a/cucumber-android/src/test/java/cucumber/runtime/android/AndroidObjectFactoryTest.java +++ /dev/null @@ -1,138 +0,0 @@ -package cucumber.runtime.android; - -import android.app.Instrumentation; -import android.content.Context; -import android.content.Intent; -import android.test.ActivityInstrumentationTestCase2; -import android.test.AndroidTestCase; -import android.test.InstrumentationTestCase; -import cucumber.api.java.ObjectFactory; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.mockito.internal.stubbing.answers.Returns; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@SuppressWarnings("deprecation") -@RunWith(RobolectricTestRunner.class) -@Config(manifest = Config.NONE) -public class AndroidObjectFactoryTest { - - private final ObjectFactory delegate = mock(ObjectFactory.class); - private final Instrumentation instrumentation = mock(Instrumentation.class); - private final AndroidObjectFactory androidObjectFactory = new AndroidObjectFactory(delegate, instrumentation); - - @Test - public void delegates_start_call() { - - // when - androidObjectFactory.start(); - - // then - verify(delegate).start(); - } - - @Test - public void delegates_stop_call() { - - // when - androidObjectFactory.stop(); - - // then - verify(delegate).stop(); - } - - @Test - public void delegates_addClass_call() { - - // given - final Class someClass = String.class; - - // when - androidObjectFactory.addClass(someClass); - - // then - verify(delegate).addClass(String.class); - } - - @Test - public void delegates_getInstance_call() { - - // given - final Class someClass = String.class; - - // when - androidObjectFactory.getInstance(someClass); - - // then - verify(delegate).getInstance(someClass); - - } - - @Test - public void injects_instrumentation_into_ActivityInstrumentationTestCase2() { - - // given - final Class activityInstrumentationTestCase2Class = ActivityInstrumentationTestCase2.class; - final ActivityInstrumentationTestCase2 activityInstrumentationTestCase2 = mock(ActivityInstrumentationTestCase2.class); - when(delegate.getInstance(activityInstrumentationTestCase2Class)).then(new Returns(activityInstrumentationTestCase2)); - - // when - androidObjectFactory.getInstance(activityInstrumentationTestCase2Class); - - // then - verify(activityInstrumentationTestCase2).injectInstrumentation(instrumentation); - } - - @Test - public void sets_activity_intent_with_FLAG_ACTIVITY_CLEAR_TOP_to_prevent_stalling_when_calling_getActivity_if_the_activity_is_already_running() { - - // given - final Class activityInstrumentationTestCase2Class = ActivityInstrumentationTestCase2.class; - final ActivityInstrumentationTestCase2 activityInstrumentationTestCase2 = mock(ActivityInstrumentationTestCase2.class); - when(delegate.getInstance(activityInstrumentationTestCase2Class)).then(new Returns(activityInstrumentationTestCase2)); - - // when - androidObjectFactory.getInstance(activityInstrumentationTestCase2Class); - - // then - verify(activityInstrumentationTestCase2).setActivityIntent(Mockito.argThat(argument -> argument.getFlags()==Intent.FLAG_ACTIVITY_CLEAR_TOP)); - } - - @Test - public void injects_instrumentation_into_InstrumentationTestCase() { - - // given - final Class instrumentationTestCaseClass = InstrumentationTestCase.class; - final InstrumentationTestCase instrumentationTestCase = mock(InstrumentationTestCase.class); - when(delegate.getInstance(instrumentationTestCaseClass)).then(new Returns(instrumentationTestCase)); - - // when - androidObjectFactory.getInstance(instrumentationTestCaseClass); - - // then - verify(instrumentationTestCase).injectInstrumentation(instrumentation); - } - - @Test - public void injects_instrumentation_context_into_AndroidTestCase() { - - // given - final Class androidTestCaseClass = AndroidTestCase.class; - final AndroidTestCase androidTestCase = mock(AndroidTestCase.class); - when(delegate.getInstance(androidTestCaseClass)).then(new Returns(androidTestCase)); - final Context context = mock(Context.class); - when(instrumentation.getTargetContext()).thenReturn(context); - - // when - androidObjectFactory.getInstance(androidTestCaseClass); - - // then - verify(androidTestCase).setContext(context); - - } -} \ No newline at end of file diff --git a/cukeulator/build.gradle b/cukeulator/build.gradle index d5bcb93..eef7e1c 100644 --- a/cukeulator/build.gradle +++ b/cukeulator/build.gradle @@ -13,7 +13,7 @@ android { defaultConfig { applicationId "cucumber.cukeulator" testApplicationId "cucumber.cukeulator.test" - testInstrumentationRunner "cucumber.api.android.CucumberAndroidJUnitRunner" + testInstrumentationRunner "cucumber.cukeulator.test.CukeulatorAndroidJUnitRunner" } packagingOptions { @@ -66,14 +66,12 @@ dependencies { // automatically by Gradle, the flag always bypasses any caching of dependencies. - implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'androidx.appcompat:appcompat:1.0.2' // testImplementation 'junit:junit:4.12' // testImplementation 'org.mockito:mockito-core:2.10.0' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test:rules:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - androidTestImplementation 'com.android.support:support-annotations:27.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + androidTestImplementation 'androidx.test:rules:1.1.1' // Use the stable Cucumber version androidTestImplementation project(":cucumber-android") diff --git a/cukeulator/src/androidTest/java/cucumber/cukeulator/test/CalculatorActivitySteps.java b/cukeulator/src/androidTest/java/cucumber/cukeulator/test/CalculatorActivitySteps.java index 7912ebc..c7b889e 100644 --- a/cukeulator/src/androidTest/java/cucumber/cukeulator/test/CalculatorActivitySteps.java +++ b/cukeulator/src/androidTest/java/cucumber/cukeulator/test/CalculatorActivitySteps.java @@ -1,10 +1,7 @@ package cucumber.cukeulator.test; import android.app.Activity; -import android.support.test.rule.ActivityTestRule; - -import org.junit.Rule; - +import androidx.test.rule.ActivityTestRule; import cucumber.api.java.After; import cucumber.api.java.Before; import cucumber.api.java.en.Given; @@ -13,11 +10,11 @@ import cucumber.cukeulator.CalculatorActivity; import cucumber.cukeulator.R; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; import static org.junit.Assert.assertNotNull; /** @@ -34,7 +31,7 @@ public class CalculatorActivitySteps { /** - * Since {@link CucumberRunner} and {@link cucumber.api.android.CucumberInstrumentationCore} have the control over the + * Since {@link cucumber.runtime.android.CucumberJUnitRunner} and {@link cucumber.api.android.CucumberInstrumentationCore} have the control over the * test lifecycle, activity test rules must not be launched automatically. Automatic launching of test rules is only * feasible for JUnit tests. Fortunately, we are able to launch the activity in Cucumber's {@link Before} method. */ diff --git a/cukeulator/src/androidTest/java/cucumber/cukeulator/test/CucumberRunner.java b/cukeulator/src/androidTest/java/cucumber/cukeulator/test/CukeulatorAndroidJUnitRunner.java similarity index 64% rename from cukeulator/src/androidTest/java/cucumber/cukeulator/test/CucumberRunner.java rename to cukeulator/src/androidTest/java/cucumber/cukeulator/test/CukeulatorAndroidJUnitRunner.java index 1056a43..12444f9 100644 --- a/cukeulator/src/androidTest/java/cucumber/cukeulator/test/CucumberRunner.java +++ b/cukeulator/src/androidTest/java/cucumber/cukeulator/test/CukeulatorAndroidJUnitRunner.java @@ -1,40 +1,27 @@ package cucumber.cukeulator.test; import android.os.Bundle; -import android.support.test.runner.MonitoringInstrumentation; import cucumber.api.CucumberOptions; -import cucumber.api.android.CucumberInstrumentationCore; +import cucumber.api.android.CucumberAndroidJUnitRunner; import java.io.File; /** - * A modern replacement for {@link cucumber.api.android.CucumberInstrumentation}. - * Supports Cucumber steps without base classes plus activity test rules. - *

+ * Android JUnit compatible replacement for {@link cucumber.api.android.CucumberInstrumentation}. * The CucumberOptions annotation is mandatory for exactly one of the classes in the test project. * Only the first annotated class that is found will be used, others are ignored. If no class is * annotated, an exception is thrown. - */ +*/ @CucumberOptions( features = "features" ) -public class CucumberRunner extends MonitoringInstrumentation { +public class CukeulatorAndroidJUnitRunner extends CucumberAndroidJUnitRunner { - private final CucumberInstrumentationCore instrumentationCore = new CucumberInstrumentationCore(this); @Override public void onCreate(final Bundle bundle) { bundle.putString("plugin", getPluginConfigurationString()); // we programmatically create the plugin configuration super.onCreate(bundle); - instrumentationCore.create(bundle); - start(); - } - - @Override - public void onStart() { - super.onStart(); - waitForIdleSync(); - instrumentationCore.start(); } /** @@ -44,10 +31,9 @@ public void onStart() { * @return the plugin string for the configuration, which contains XML, HTML and JSON paths */ private String getPluginConfigurationString() { - final String cucumber = "cucumber"; - final String separator = "--"; - return - "junit:" + getAbsoluteFilesPath() + "/" + cucumber + ".xml" + separator + + String cucumber = "cucumber"; + String separator = "--"; + return "junit:" + getAbsoluteFilesPath() + "/" + cucumber + ".xml" + separator + "html:" + getAbsoluteFilesPath() + "/" + cucumber + ".html" + separator + "json:" + getAbsoluteFilesPath() + "/" + cucumber + ".json"; } @@ -63,5 +49,4 @@ private String getAbsoluteFilesPath() { File directory = getTargetContext().getExternalFilesDir(null); return new File(directory,"reports").getAbsolutePath(); } - -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index 1d3591c..915f0e6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,4 +15,6 @@ # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file +# org.gradle.parallel=true +android.enableJetifier=true +android.useAndroidX=true \ No newline at end of file