robolectric / robolectric

Android Unit Testing Framework

Home Page:http://robolectric.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AndroidManifest.xml not found in RobolectricGradleTestRunner

davidschreiber opened this issue · comments

Android Studio: 1.2 Preview 4
Gradle Plugin: 1.1.0
Robolectric: 3.0-rc1

When trying to run Robolectric unit tests within Android Studio the test runner fails with following error message:

java.io.FileNotFoundException: build/intermediates/bundles/debug/AndroidManifest.xml (No such file or directory)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)

java.lang.UnsupportedOperationException: Robolectric does not support API level 1.
    at org.robolectric.internal.SdkConfig.<init>(SdkConfig.java:28)
    at org.robolectric.RobolectricTestRunner.pickSdkVersion(RobolectricTestRunner.java:439)
    at org.robolectric.RobolectricTestRunner.getEnvironment(RobolectricTestRunner.java:274)
    at org.robolectric.RobolectricTestRunner.access$300(RobolectricTestRunner.java:50)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:193)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:168)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

    at org.robolectric.res.FileFsFile.getInputStream(FileFsFile.java:78)
    at org.robolectric.manifest.AndroidManifest.parseAndroidManifest(AndroidManifest.java:132)
    at org.robolectric.manifest.AndroidManifest.getTargetSdkVersion(AndroidManifest.java:485)
    at org.robolectric.RobolectricTestRunner.pickSdkVersion(RobolectricTestRunner.java:439)
    at org.robolectric.RobolectricTestRunner.getEnvironment(RobolectricTestRunner.java:274)
    at org.robolectric.RobolectricTestRunner.access$300(RobolectricTestRunner.java:50)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:193)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:168)

This happens with my own test setup as well as with the robolectric-samples.

As far as I understand the RobolectricGradleTestRunner tries to read the merged manifest from <projectRoot>/build/intermediates/manifests/full/debug/AndroidManifest.xml whereas the manifest resides within the modules build folder located under <projectRoot>/app/build/intermediates/manifests/full/debug/AndroidManifest.xml (notice the app in the path). Therefore, it is not able to find the correct manifest and used SDK version.

Also the RobolectricGradleTestRunner seems to ignore the manifest defined within the @Config annotation, making it impossible to start tests.

In order to run the tests from within Android Studio, it is necessary to set the working directory within the test's run configuration to the module directory.

run_debug_configurations

This should only be true for Mac user and is documented at https://github.com/robolectric/robolectric/wiki/Running-tests-in-Android-Studio

But I don't like to do "not necessary" customization which must be applied from each developer that the reason why I use a custom runner https://github.com/nenick/AndroidStudioAndRobolectric/blob/master/app/src/test/java/com/example/myapplication/CustomRobolectricRunner.java

Thanks, I am now also using a custom test runner which also works around problems with the applicationIdSuffix for debug build types (Robolectric would fail to resolve resources because of this). Once the 3.0 release reaches a stable version I would recommend updating the documentation on the official site (if the Mac problem is not resolved till then).

Also the RobolectricGradleTestRunner seems to ignore the manifest defined within the @config annotation, making it impossible to start tests.

This is by design. The standard RobolectricTestRunner still exists if you want to configure everything yourself. Note that you don't have to hard-code the 'working directory' value - you can set it to $MODULE_DIR$ which will do the same thing.

I believe I've found a related bug in this area: if you run gradle with -PbuildDir=foo to customize the build output directory, Robolectric fails with the error above (e.g. it's looking for literally the 'build' directory).

I am actually trying to resolve this for one of my customers, not my own app. If this has been fixed in a newer version of Robolectric or dependent library, please comment here and I'll pass the info along to my customer.

Alternatively, if this doesn't fail for you, it means there's something else wonky about my customer's configuration (and I'd like to know that I'm barking up the wrong tree here).

Thanks!

Has this been fixed yet? i get the same error where it cant find my manifest even if i declare it on the Config annotation

As long as you're not using a custom build dir like @stamhankar999, this has been fixed for awhile. You need to use RobolectricGradleTestRunner and configure Android Studio as shown in http://robolectric.org/getting-started/ (read the Building with Android Studio section). Also, the robolectric-samples project has a ton of examples that all work in AS.

hiya i am not using a custom build directory and i am using RobolectricGradleTestRunner. will test the samples and see if those work

commented

@erd This issue should be opened again.

It does work from terminal with gradlew testDebug but it doesn't work from Android Studio 1.3 (5.0, latest version) with android plugin 1.3.0-beta1.

It ignores manifest path set in robolectric.properties or using @Config annotation. It always fails with the same error.

java.lang.RuntimeException: build/intermediates/bundles/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
    at org.robolectric.manifest.AndroidManifest.validate(AndroidManifest.java:120)
    at org.robolectric.manifest.AndroidManifest.getResourcePath(AndroidManifest.java:469)
    at org.robolectric.manifest.AndroidManifest.getIncludedResourcePaths(AndroidManifest.java:475)
    at org.robolectric.RobolectricTestRunner.createAppResourceLoader(RobolectricTestRunner.java:479)
    at org.robolectric.RobolectricTestRunner.getAppResourceLoader(RobolectricTestRunner.java:471)
    at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:73)
    at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:421)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:234)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:185)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:149)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

java.lang.RuntimeException: java.lang.RuntimeException: build/intermediates/bundles/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:238)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:185)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:149)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.RuntimeException: build/intermediates/bundles/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
    at org.robolectric.manifest.AndroidManifest.validate(AndroidManifest.java:120)
    at org.robolectric.manifest.AndroidManifest.getResourcePath(AndroidManifest.java:469)
    at org.robolectric.manifest.AndroidManifest.getIncludedResourcePaths(AndroidManifest.java:475)
    at org.robolectric.RobolectricTestRunner.createAppResourceLoader(RobolectricTestRunner.java:479)
    at org.robolectric.RobolectricTestRunner.getAppResourceLoader(RobolectricTestRunner.java:471)
    at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:73)
    at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:421)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:234)
    ... 18 more

Agreed. This still doesn't work
On 19 Jun 2015 18:12, "Tomasz Rozbicki" notifications@github.com wrote:

@erd https://github.com/erd This issue should be opened again.

It does work from terminal with gradlew testDebug but it doesn't work
from Android Studio 1.3 (5.0, latest version) with android plugin
1.3.0-beta1.

It ignores manifest path set in robolectric.properties or using @config
annotation. It always fails with the same error.

java.lang.RuntimeException: build/intermediates/bundles/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
at org.robolectric.manifest.AndroidManifest.validate(AndroidManifest.java:120)
at org.robolectric.manifest.AndroidManifest.getResourcePath(AndroidManifest.java:469)
at org.robolectric.manifest.AndroidManifest.getIncludedResourcePaths(AndroidManifest.java:475)
at org.robolectric.RobolectricTestRunner.createAppResourceLoader(RobolectricTestRunner.java:479)
at org.robolectric.RobolectricTestRunner.getAppResourceLoader(RobolectricTestRunner.java:471)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:73)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:421)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:234)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:185)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:149)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

java.lang.RuntimeException: java.lang.RuntimeException: build/intermediates/bundles/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:238)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:185)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:149)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.RuntimeException: build/intermediates/bundles/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
at org.robolectric.manifest.AndroidManifest.validate(AndroidManifest.java:120)
at org.robolectric.manifest.AndroidManifest.getResourcePath(AndroidManifest.java:469)
at org.robolectric.manifest.AndroidManifest.getIncludedResourcePaths(AndroidManifest.java:475)
at org.robolectric.RobolectricTestRunner.createAppResourceLoader(RobolectricTestRunner.java:479)
at org.robolectric.RobolectricTestRunner.getAppResourceLoader(RobolectricTestRunner.java:471)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:73)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:421)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:234)
... 18 more


Reply to this email directly or view it on GitHub
#1648 (comment)
.

commented

Ok, there are two possible solutions:

  • Edit "Working directory" in "Run/Debug configuration"
/home/toro/workspace/bb/priv/MODULE_NAME

or

$MODULE_DIR$

cons: you have to do it manually for every run configuration

  • Create custom runner with different BUILD_OUTPUT. This value should be set to MODULE_NAME/build/intermediates

pros: always works, you can forget about changing working directory

public class MyRunner extends RobolectricTestRunner {

    private static final String BUILD_OUTPUT = "app/build/intermediates";

    public MyRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    protected AndroidManifest getAppManifest(Config config) {
        if (config.constants() == Void.class) {
            Logger.error("Field 'constants' not specified in @Config annotation");
            Logger.error("This is required when using RobolectricGradleTestRunner!");
            throw new RuntimeException("No 'constants' field in @Config annotation!");
        }

        final String type = getType(config);
        final String flavor = getFlavor(config);
        final String packageName = getPackageName(config);

        final FileFsFile res;
        final FileFsFile assets;
        final FileFsFile manifest;

        if (FileFsFile.from(BUILD_OUTPUT, "res").exists()) {
            res = FileFsFile.from(BUILD_OUTPUT, "res", flavor, type);
        } else {
            res = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "res");
        }

        if (FileFsFile.from(BUILD_OUTPUT, "assets").exists()) {
            assets = FileFsFile.from(BUILD_OUTPUT, "assets", flavor, type);
        } else {
            assets = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "assets");
        }

        if (FileFsFile.from(BUILD_OUTPUT, "manifests").exists()) {
            manifest = FileFsFile.from(BUILD_OUTPUT, "manifests", "full", flavor, type, "AndroidManifest.xml");
        } else {
            manifest = FileFsFile.from(BUILD_OUTPUT, "bundles", flavor, type, "AndroidManifest.xml");
        }

        Logger.debug("Robolectric assets directory: " + assets.getPath());
        Logger.debug("   Robolectric res directory: " + res.getPath());
        Logger.debug("   Robolectric manifest path: " + manifest.getPath());
        Logger.debug("    Robolectric package name: " + packageName);
        return new AndroidManifest(manifest, res, assets, packageName);
    }

    private String getType(Config config) {
        try {
            return ReflectionHelpers.getStaticField(config.constants(), "BUILD_TYPE");
        } catch (Throwable e) {
            return null;
        }
    }

    private String getFlavor(Config config) {
        try {
            return ReflectionHelpers.getStaticField(config.constants(), "FLAVOR");
        } catch (Throwable e) {
            return null;
        }
    }

    private String getPackageName(Config config) {
        try {
            final String packageName = config.packageName();
            if (packageName != null && !packageName.isEmpty()) {
                return packageName;
            } else {
                return ReflectionHelpers.getStaticField(config.constants(), "APPLICATION_ID");
            }
        } catch (Throwable e) {
            return null;
        }
    }
}

Ok, there are two possible solutions:

Edit "Working directory" in "Run/Debug configuration"

FWIW: This is documented at http://robolectric.org/getting-started/

commented

You're right, that's why I've added it.

If you create a lot of run configurations on the fly this is pain in the a*s.

You can edit the default run configuration so that all of the ones created on the fly already have the path set.

commented

@sparkym3 Could you please provide information how to set it? I've not found any settings in AS. I'll stay with custom runner, because it works for every other team member without any additional actions, but it may be useful to other developers as well.

You have to set working directory to $MODULE_DIR$ in Windows too. http://robolectric.org/getting-started/ should say that.