Cannot spy on Android Activity in ActivityInstrumentationTestCase2 - android

I'm trying to spy on an Activity but it gives me the following exception:
java.lang.AbstractMethodError: abstract method "boolean org.mockito.internal.invocation.AbstractAwareMethod.isAbstract()"
at org.mockito.internal.invocation.InvocationImpl.callRealMethod(InvocationImpl.java:109)
at org.mockito.internal.stubbing.answers.CallsRealMethods.answer(CallsRealMethods.java:41)
at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:93)
at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:38)
at com.google.dexmaker.mockito.InvocationHandlerAdapter.invoke(InvocationHandlerAdapter.java:49)
at WaitForCardActivity_Proxy.isRegisterActivated(WaitForCardActivity_Proxy.generated)
The code is as follows:
#RunWith(AndroidJUnit4.class)
public class WaitForCardActivityTests extends ActivityInstrumentationTestCase2<WaitForCardActivity> {
#Before
#Override
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
waitForCardActivity = spy(getActivity());
when(waitForCardActivity.isRegisterActivated()).thenReturn(true);
}
...
}
Activity:
public class WaitForCardActivity extends Activity {
...
public boolean isRegisterActivated() {
...
}
}
Also note: I cannot use Robolectric because I'm using Ciphers which give me problems when running with Robolectric.

Spy Activity in following way:
Activity activity = spy(Activity.class);
Update:
And in your case:
WaitForCardActivity activity = spy(WaitForCardActivity.class);
when(activity.isRegisterActivated()).thenReturn(true);
assertTrue(activity.isRegisterActivated());

Related

Android, Espresso - Activity stops before whole test is finished when run as part of :app:connectedAndroidTest (runs fine in isolation)

I apologise if this is a bit too vague here, but I'm not allowed to post my whole actual code. All I can say is I have a problem running this test as a part of ./gradlew connectedAndroidTest
#RunWith(AndroidJUnit4.class)
#LargeTest
public class MobileAppSanityTest extends AbstractEspressoTest {
#Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ClearPreferencesActivityTestRule<>(MainActivity.class, getFiles());
#Override
protected Context getContext() {
return mActivityRule.getActivity();
}
#BeforeClass
public static void beforeAll() {
RoboGuice.Util.reset();
}
#Test
public void test_SingleUserFlow() {
navigateSplashScreen();
logIn();
doSomethingElse();
}
}
What happens here is that when I run this test class on its own - it runs fine, but when I run it as a part of 'connectedAndroidTest' the activity is stopped right after 'navigateSplashScreen' and login cannot be performed.
Error I get is:
java.lang.RuntimeException: No activities found. Did you t to launch the activity by calling getActivity() or startActivitySync or similar?
I'm quite new to Espresso and Android in general, so it's a bit hard to wrap my head around this. Please let me know if you need more information. I'll try to provide it out if that's the case.
a jUnit TestCase looks differently; think one can only use Espresso in there.
#RunWith(AndroidJUnit4.class)
public class MainActivityTest extends TestCase {
/** Log Tag */
private static final String LOG_TAG = MainActivityTest.class.getSimpleName();
/** the Activity of the Target application */
private MainActivity mActivity;
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<MainActivity>(MainActivity.class) {
};
#Override
public void setUp() throws Exception {
super.setUp();
}
/* obtaining the context from the ActivityTestRule */
#Before
public void setUpTest() {
this.mActivity = this.mActivityRule.getActivity();
}
/* add Espresso code eg. here */
#Test
#UiThreadTest
public void navigateSplashScreen() {
}
#Override
public void tearDown() throws Exception {
super.tearDown();
}
}

Is there a way to run Espresso test with multiple test methods but only one setup method?

I have a simple test today:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class WhenNavigatingToUsersView {
#Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule(MainActivity.class);
private MainActivity mainActivity;
#Before
public void setActivity() {
mainActivity = mActivityRule.getActivity();
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.users)))).perform(click());
}
#Test
public void thenCorrectViewTitleShouldBeShown() {
onView(withText("This is the Users Activity.")).check(matches(isDisplayed()));
}
#Test
public void thenCorrectUserShouldBeShown() {
onView(withText("Donald Duck (1331)")).check(matches(isDisplayed()));
}
}
But for every test method the setActivity is run, which, if you have 10-15 methods, in the end will be time consuming (if you have a lot of views too).
#BeforeClass doesn't seem to work since it has to be static and thus forcing the ActivityTestRule to be static as well.
So is there any other way to do this? Rather than having multiple asserts in the same test method?
#Before annotation should only precede methods containing preliminary setup. Initialization of needed objects, getting the current session or the current activity, you get the idea.
It is replacing the old setUp() method from the ActivityInstrumentationTestCase2, just as #After replaces the tearDown().
That means that it is intended to be executed before every test in the class and it should stay that way.
You should have no ViewInteraction, no DataInteraction, no Assertions nor View actions in this method, since that is not its purpose.
In your case, simply remove the onView() call from setActivity() and put it inside the actual test methods, in every test method if necessary, like so:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class WhenNavigatingToUsersView {
#Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule(MainActivity.class);
private MainActivity mainActivity;
#Before
public void setActivity() {
mainActivity = mActivityRule.getActivity();
// other required initializations / definitions
}
#Test
public void thenCorrectViewTitleShouldBeShown() {
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.users)))).perform(click());
onView(withText("This is the Users Activity.")).check(matches(isDisplayed()));
}
#Test
public void thenCorrectUserShouldBeShown() {
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.users)))).perform(click());
onView(withText("Donald Duck (1331)")).check(matches(isDisplayed()));
}
}
Another option for you would be separating these tests.
Clicking on the user's icon will be in the HomeActivity test class while the rest of the tests will be in the UserActivity test class.
UserActivity test class will launch UserActivity with the proper Intent ( you can do so by passing the false Boolean into the Rule constructor and calling launchActivity(intent) manually).
This will eliminate the necessity of setting up the activity every single time. It will also get rid of constant dependency on the main activity. If something goes wrong, your UserActivity tests will be intact and will produce the results, while the issue will be caught by the test in the MainActivity.
Actually, by doing so your tests will might become MediumSize as the runtime will drastically decrease.
You can try this :
**** Setting ****
public void testStory() throws Exception {
}
public void testStory2() throws Exception {
}
public void testStory3() throws Exception {
}
Try to run your test by this command:
./gradlew cC
Did you try doing it as follows or a minor variation of it to suit your needs:
#Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class);
private MainActivity mainActivity = mActivityRule.getActivity();
#BeforeClass
public static void setActivity() {
onView(allOf(withId(R.id.icon), hasSibling(withText(R.string.users)))).perform(click());
}
This way, you 'mainActivity' need not be static. Also, the setActivity() method will get called only once.

Testing Android Activity with Robolectric, duplicated Otto provider

I have a little problem figuring out how to test my Activity using Robolectric 2.2. I am probably not correctly setting up the lifecycle or the entire test...
In my Activity, I have a Otto producer like this:
#Produce public GetAlarmList produceAlarmList() {
Log.v(this, "Producing GetAlarmList event.");
return new GetAlarmList(mAlarmList);
}
The following is my test.
#RunWith(RobolectricTestRunner.class)
public class GLarmListFragmentTests {
//GLarmMain mActivity;
ActivityController<GLarmMain> mController;
#Before
public void setUp() throws Exception {
mController = Robolectric.buildActivity(GLarmMain.class);
}
#After
public void tearDown() throws Exception {
mController = mController.destroy();
}
#Test
public void shouldHaveListFragment() {
GLarmMain activity = mController.create().start().resume().visible().get();
GLarmListFragment listFragment = (GLarmListFragment) activity.getSupportFragmentManager().findFragmentById(R.id.main_list_frag);
assertNotNull(listFragment);
}
#Test
public void shouldHaveListAdapter() {
GLarmMain activity = mController.create().start().resume().visible().get();
GLarmListFragment listFragment = (GLarmListFragment) activity.getSupportFragmentManager().findFragmentById(R.id.main_list_frag);
FuncAlarmListAdapter listAdapter = (FuncAlarmListAdapter)listFragment.getListAdapter();
assertNotNull(listAdapter);
}
}
Every time I launch it, I receive:
java.lang.IllegalArgumentException: Producer method for type class ar.android.app.glarm.events.GetAlarmList found on type class ar.android.app.glarm.ui.GLarmMain, but already registered by type class ar.android.app.glarm.ui.GLarmMain.
at com.squareup.otto.Bus.register(Bus.java:198)
at ar.android.app.glarm.ui.GLarmMain.onResume(GLarmMain.java:461)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1184)
at android.app.Activity.performResume(Activity.java:5082)
at org.fest.reflect.method.Invoker.invoke(Invoker.java:112)
at org.robolectric.util.ActivityController$6.run(ActivityController.java:216)
at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:256)
at org.robolectric.util.ActivityController.invokeWhilePaused(ActivityController.java:214)
at org.robolectric.util.ActivityController.resume(ActivityController.java:152)
at ar.android.app.glarm.test.GLarmListFragmentTests.shouldHaveListAdapter(GLarmListFragmentTests.java:51)
Does someone have the same issue? How can I solve it?
Found the problem, leaving it here for reference.
I was not handling the pause()/onPause() life-cycle step and therefore never calling:
#Override
protected void onPause() {
super.onPause();
Log.v(this, ".onPause()");
mBus.unregister(this); // unregisters.
}
Changing the above code as following solved:
#After
public void tearDown() throws Exception {
mController = mController.pause().stop().destroy();
}

Is it possible to test an Abstract activity with Robolectric

I use abstract activity classes in my code to well, abstract away some features from the activity classes.
I'm trying to test the abstract activity classes using Robolectric and the gradle-android-test-plugin using subclasses that extend the abstract class. I can't seem to get it to work though.
Does anyone have any experience in this area and is it even possible ? Basic structure is :
#RunWith(RobolectricGradleTestRunner.class)
public class AbstractActivityTest {
private ActivityTest activity;
#Before
public void setUp() throws Exception {
activity = Robolectric.buildActivity(ActivityTest.class).create().get();
}
private class ActivityTest extends AbstractActivity {
// do something
}
}
Initially, I got the error message the sub class wasn't static so I made it static. Now I get the following two fails:
initializationError FAILED
java.lang.Exception: Test class should have exactly one public constructor
initializationError FAILED
java.lang.Exception: No runnable methods
Any obviously true tests I put in #Test methods succeed.
The first error saying that you added non-default constructor to your test class or changed access level for default one. But as it says junit Test class should have at least one public constructor.
The second one says that at least one method in test class should have #Test annotation (junit 4) or starts with test substring (junit 3).
Yo can doing exactly what you are trying to do: subclass the abstract activity and instance the concrete class.
However, you need to declare the class extending the abstract Activity in it's own public file. If it's a nested class Robolectric will fail to instance it.
I don't know why, though.
I test an abstract activity this way:
1. Creating the abstract avtivity:
public abstract class AbstractActivity extends AppCompatActivity {
public int getNumber() {
return 2;
}
}
2. Creating the test class:
You just need to declare a static nested subclass of your abstract class.
#RunWith(RobolectricTestRunner.class)
public class AbstractActivityTest {
#Test
public void checkNumberReturn() throws Exception {
TestAbstractActivity testAbstractActivity = Robolectric.setupActivity(TestAbstractActivity.class);
assertThat(testAbstractActivity.getNumber(), is(2));
}
public static class TestAbstractActivity extends AbstractActivity {
}
}

Testing a fragment (Android), mocking getActivity() call

I want to test a Fragment with AndroidTest cases and Mockito (I am using mockito for other test cases).
I´ve done this before with my own code (coded in a different way) but in this case, I am testing a Fragment and I want to mock this call: final PackageManager packageManager = getActivity().getPackageManager();
I will put you here part of the TestClass, and part of the Fragment that I want to test.
Thanks in advance for your ideas or suggestions.
public class MyFragmentTest extends
ActivityInstrumentationTestCase2<MyActivity>{
MyFragment myFragment;
public MyFragmentTest () {
super(MyActivity.class);
}
#Override
public void setUp() throws Exception {
super.setUp();
// This have to be done because of some issues with dexmaker
System.setProperty("dexmaker.dexcache", "/sdcard");
// This have to be done because of the sharedUserId problem
Thread.currentThread().setContextClassLoader(
getClass().getClassLoader());
myFragment = new MyFragment() {
//I can override methods here
};
}
public void testMyMethod() throws Exception {
myFragment.methodThatIWantToTest();
}
}
/************ CLASS THAT I WANT TO TEST *********/
public class MyFragment extends Fragment{
public void methodThatIWantToTest(){
/*..... more lines */
final PackageManager packageManager = getActivity().getPackageManager();
/*..... more lines ...*/
}
}
I have employed this hack:
// Needed because Fragment.mActivity is package-private
package android.support.v4.app;
public class FragmentInjector {
public static void injectActivity(Fragment fragment, FragmentActivity fragmentActivity) {
fragment.mActivity = fragmentActivity;
}
}
Alternatively you could employ reflection to change the value of fragment.mActivity. I don't know of any other way.

Categories

Resources