[Cucumber][Android] Annotations flow in Instrumentation dependency

230 views
Skip to first unread message

Tim Walker

unread,
Nov 14, 2016, 7:23:48 AM11/14/16
to Cukes
Hi, 

I am hoping someone can help me understand how annotations get passed (in Android instrumentation, generally). I have the following two methods implementing the runner (extending TestCase) and Instrumentation (extending instrumentationTestRunner). In my Test configuration one is the runner and one is the instrumentation class. When it runs I get the "onStart ExceptionNo CucumberOptions annotation" in my adb logcat. My question is: How does the @CucumberOptions get passed through to the Instrumentation? I just don't understand this. I looked at the code (copied below at the bottom) that does, though I don't understand how that works (I mean, I see it iterating through the dependency tree but I always assumed annotations were just one and done in the class that called them) and why this is failing. Any help appreciated. Thanks in advance. Your pal, Tim. 

---------------------- 
package com.theagiletester.discalive.app.stepDefinitions.runner;

import junit.framework.TestCase;
import cucumber.api.CucumberOptions;

@CucumberOptions(
glue = "com.theagiletester.discalive.stepDefinitions",
plugin = {
"pretty",
"html:" + CucumberInstrumentedTestRunner.REPORT_PATH + "cucumber-html-report",
"pretty:" + CucumberInstrumentedTestRunner.REPORT_PATH + "cucumber-report.json",
"junit:" + CucumberInstrumentedTestRunner.REPORT_PATH + "cucumber.xml"
},
features = "features",
tags = "@shortSanity")
public class CucumberInstrumentedTestRunner extends TestCase {
public static final String REPORT_PATH = "data/data/cucumber-reports/";
}
------------

package com.theagiletester.discalive.app.helpers;

import android.os.Bundle;
import android.support.test.runner.AndroidJUnitRunner;
import android.support.test.runner.MonitoringInstrumentation;
import android.test.InstrumentationTestCase;
import android.test.InstrumentationTestRunner;
import android.util.Log;

import cucumber.api.CucumberOptions;
import cucumber.api.android.CucumberInstrumentationCore;

public class Instrumentation extends InstrumentationTestRunner {

private final CucumberInstrumentationCore instrumentationCore = new CucumberInstrumentationCore(this);

@Override
public void onCreate(final Bundle bundle) {
try {
super.onCreate(bundle);
Log.d("Bundle: ", bundle.getClass().toString());
instrumentationCore.create(bundle);
} catch(Exception e) { Log.d("Cucumber:", "onStart Exception" + e.getMessage()); }
}

@Override

public void onStart() {
try {
waitForIdleSync();
instrumentationCore.start();
}
catch(Exception e) { Log.d("Cucumber:", "onStart Exception" + e.getMessage()); }
}

}

---------------
Class<?> optionsAnnotatedClass = null;
        for (Class<?> clazz : classFinder.getDescendants(Object.class, context.getPackageName())) {
            if (clazz.isAnnotationPresent(CucumberOptions.class)) {
                Log.d(TAG, "Found CucumberOptions in class " + clazz.getName());
                Log.d(TAG, clazz.getAnnotations()[0].toString());
                optionsAnnotatedClass = clazz;
                break; // We assume there is only one CucumberOptions annotated class.
            }
        }
        if (optionsAnnotatedClass == null) {
            throw new CucumberException("No CucumberOptions annotation");
        }
---------------

Tim Walker

unread,
Nov 14, 2016, 7:54:35 AM11/14/16
to cu...@googlegroups.com

Hi Guys, 

I got this running last night. Hopefully this will help someone else. 

See InLine below. 

According to https://github.com/cucumber/cucumber-jvm/tree/master/android I should add sections to the AndroidManifest in the androidTest context but I could not get androidStudio to recognize these. I suspect the "packageName" resolves the annotations problem but I just couldn't get that to work:

<instrumentation
    android:name="cucumber.api.android.CucumberInstrumentation"
    android:targetPackage="<Your tested application package name>" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <uses-library android:name="android.test.runner" />
</application>


However, I added some diagnostics in my Instrumentation onCreate (see below) and I saw that the context was com.theagiletester.discalive.test. The "test" context even though these are androidTests. When I moved my Runner and Instrumentation file to a folder named test, it recognized my @CucumberOptions annotations. 

Context inst_context = InstrumentationRegistry.getTargetContext();
Log.d("Cucumber: ", "Instrumentation Context Package " + context.getPackageName());

Inline image 1 

Then I added the testInstrumentationRunner to my build.config: 
defaultConfig {
applicationId "com.theagiletester.discalive"
minSdkVersion 18
targetSdkVersion 19
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "com.theagiletester.discalive.test.CucumberInstrumentation"
}
And created a sourceSet for my assets in androidTests:
sourceSets {
androidTest {
assets.srcDirs = ['src/androidTest/java/com/theagiletester/discalive/assets/']
}
}
And now it's working though I still have a lot to learn on Android. Thanks very much, Tim
>  @Override
>
>  public void onStart() {
>  try {
>  waitForIdleSync();
>  instrumentationCore.start();
>  }
>  catch(Exception e) { Log.d("Cucumber:", "onStart Exception" + e.getMessage()); }
>  }
>
> }
>
>
> ---------------
>
> Class<?> optionsAnnotatedClass = null;  for (Class<?> clazz : classFinder.getDescendants(Object.class, context.getPackageName())) {  if (clazz.isAnnotationPresent(CucumberOptions.class)) {  Log.d(TAG, "Found CucumberOptions in class " + clazz.getName());  Log.d(TAG, clazz.getAnnotations()[0].toString());  optionsAnnotatedClass = clazz;  break; // We assume there is only one CucumberOptions annotated class.  }  }  if (optionsAnnotatedClass == null) {  throw new CucumberException("No CucumberOptions annotation");  }
>
> ---------------
>
> --
> Posting rules: http://cukes.info/posting-rules.html
> ---
> You received this message because you are subscribed to the Google Groups "Cukes" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to cukes+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages