3

I'm brand new to Espresso and I'm trying to test a behavior in an abstract activity class in android.

Based on what I've read, the best way to do this is to create a class in the test file that extends the base class and implement whatever methods are needed to exercise the superclass behavior.

I have done this, but when I try to run it, I get the following error:

(Only the relevant stack trace line is shown with some private info redacted)

Caused by: java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN flg=0x14000000 cmp=com.redacted.redacted/.viewcontrollers.onboarding.BaseOnboardingActivityTest$SinglePageTestOnboarder }

Some questions seemed to indicate this was because of a missing manifest entry for the Activity, but it appears as if that was an old way of doing things and is no longer needed, though I may be misinterpreting things.

How can I fix this? I don't want the activity to be a part of the actual application, since it is only usable for testing.

Here is the test class code:

@RunWith(AndroidJUnit4::class)
class BaseOnboardingActivityTest {

    @Rule @JvmField
    var onboarderActivityTestRule = ActivityTestRule<SinglePageTestOnboarder>(SinglePageTestOnboarder::class.java)

    @Test
    fun testPageNumberDotsDoNotAppearWhenOnlyOnePage() {
        val testActivity = onboarderActivityTestRule.activity

        testActivity.pagesForOnboarding = getOnboardingTestPages(1)
        testActivity.displayPages()
        onView(withId(R.id.indicator_circle)).check(doesNotExist())

        testActivity.pagesForOnboarding = getOnboardingTestPages(2)
        testActivity.displayPages()
        onView(withId(R.id.indicator_circle)).check(matches(isDisplayed()))
    }

    class SinglePageTestOnboarder : BaseOnboardingActivity() {

        lateinit var pagesForOnboarding: List<OnboarderPageData>

        fun displayPages() {
            super.showOnboardingPages(pagesForOnboarding, "test")
        }

    }

    private fun getOnboardingTestPages(numPages: Int): List<OnboarderPageData> {
        val pages = arrayListOf<OnboarderPageData>()
        for (i in 0..numPages) {
            pages.add(OnboarderPageData())
        }
        return pages
    }

}

(I've browsed similar questions and done a lot of searching, but I believe my problem is somewhat different than these questions)

EDIT: Per request, full stack trace is below:

java.lang.RuntimeException: Could not launch activity
at android.support.test.runner.MonitoringInstrumentation.startActivitySync(MonitoringInstrumentation.java:460)
at android.support.test.rule.ActivityTestRule.launchActivity(ActivityTestRule.java:354)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:525)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at android.support.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:101)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2136)
Caused by: java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN flg=0x14000000 cmp=com.redacted.redacted/.viewcontrollers.onboarding.BaseOnboardingActivityTest$SinglePageTestOnboarder }
at android.app.Instrumentation.startActivitySync(Instrumentation.java:472)
at android.app.Instrumentation.startActivitySync(Instrumentation.java:435)
at android.support.test.runner.MonitoringInstrumentation.access$101(MonitoringInstrumentation.java:96)
at android.support.test.runner.MonitoringInstrumentation$4.call(MonitoringInstrumentation.java:436)
at android.support.test.runner.MonitoringInstrumentation$4.call(MonitoringInstrumentation.java:433)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Bassinator
  • 1,682
  • 3
  • 23
  • 50
  • "Only the relevant stack trace line is shown" -- in the future, please post the entire stack trace. You do not know what lines may be relevant for those trying to answer the question. – CommonsWare Jul 29 '18 at 21:41
  • Surely you don't need the various bubbling lines? – Bassinator Jul 29 '18 at 21:42

2 Answers2

4

Some questions seemed to indicate this was because of a missing manifest entry for the Activity

That is definitely the cause of that particular error. ActivityTestRule cannot start an activity that does not appear in the manifest.

How can I fix this?

Add the activity to your androidTest edition of your manifest. This will allow it to be used in testing, but it will not be part of your actual app itself.

That doesn't seem to be working. My guess, given your symptoms, is that the activity to be tested needs to be in the APK being tested, not in the APK containing your test code.

What I know works is to have the activity reside in the debug/ source set, as I have done this on a few occasions.

So, as a peer of main and androidTest, add a debug source set. In there, have a java/ tree with your SinglePageTestOnboarder activity. Move the androidTest manifest to the debug source set, and adjust it to have the proper android:name value.

This does mean that your "test" activity will be in the app itself, but only for debug builds. Presumably you are not shipping such builds; release builds do not include what is in the debug source set. If you do not even want this class in debug, you can create a separate build type, though that will make running the tests a bit more painful.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Hmm? There are separate manifest versions? Could you elaborate? I certainly don't want to include it in the main android manifest for the whole app, since production code should have no clue the test code exists. – Bassinator Jul 29 '18 at 21:46
  • @Airhead: "There are separate manifest versions?" -- you can have a manifest in any source set. So, just as you have `app/src/main/AndroidManifest.xml`, you can have `app/src/androidTest/AndroidManifest.xml` (for a module named `app`). The contents of the `androidTest/AndroidManifest.xml` will be merged in with the contents of the `main/AndroidManifest.xml` file when your tests are run. The contents of `androidTest/AndroidManifest.xml` will be ignored otherwise. – CommonsWare Jul 29 '18 at 21:48
  • @Airhead: Note that the `androidTest/AndroidManifest.xml` does not need to duplicate everything in `main/AndroidManifest.xml`. The `main` material will be [merged](https://developer.android.com/studio/build/manifest-merge) with the `androidTest` material. You need enough element scaffolding to get to the right spot, but your `androidTest` manifest can have `` and little else. – CommonsWare Jul 29 '18 at 21:54
  • Okay, I have done this and I'm still getting the same error. – Bassinator Jul 29 '18 at 22:04
  • I believe it has something to do with package naming? In the new manifest I have declared ` but the manifest itself has a package name of `com.redacted.redacted.test` - I'm guessing maybe something isn't being resolved properly between the two? – Bassinator Jul 29 '18 at 22:08
  • @Airhead: Try `.viewcontrollers.onboarding.BaseOnboardingActivityTest$SinglePageTestOnboarder`. That is what your error message shows as what the system is trying to resolve. – CommonsWare Jul 29 '18 at 22:10
  • Would you care to have a moment in chat? I've done that, but that gives an unresolved package error. To be clear, the exact code in the manifest entry is `` – Bassinator Jul 29 '18 at 22:13
  • @Airhead: I have [subscriber chats](https://commonsware.com/warescription), so I do not participate in Stack Overflow chats -- sorry! If you are still running into problems, consider making `SinglePageTestOnboarder` not be a nested class, instead making it be a peer of `BaseOnboardingActivityTest` (and adjust the manifest accordingly). – CommonsWare Jul 29 '18 at 22:15
  • @Airhead: "that gives an unresolved package error" -- that particular error does not ring a bell. What's the full error line? – CommonsWare Jul 29 '18 at 22:16
  • @Airhead: "in the manifest"? Do you mean that this is a compile-time problem? Anyway, if you want to fully-qualify the `android:name`, you can give that a try -- it will need to use the package in which the class itself resides, whatever that is. – CommonsWare Jul 29 '18 at 22:19
  • By in the manifest, I mean that android studio gives it's nasty red underscore - this is the message that it reads when hovered over with the cursor. Anyways, I have fully qualified the name, and moved the class into it's own file as you have suggested. However, now I get an error that the activity is not included in the manifest, when I can clearly show that it is. I assume android studio is looking at the primary manifest somehow, and not the new test one I have created. I'm just not certain how to resolve that. – Bassinator Jul 29 '18 at 22:22
0

In my case, I was using AndroidAnnotations.When @EActivity is used, another class will generate. So I should have use Activity + "_".

iman kazemayni
  • 1,255
  • 1
  • 19
  • 20