Robolectric: “AndroidManifest.xml not found” and “

2019-07-30 17:21发布

问题:

I'm running some tests with Roboletric, but I came across a issue that I can't solve. When I run the test, the following error appears with the "AndroidManifest":

WARNING: No manifest file found at .\AndroidManifest.xml.

Falling back to the Android OS resources only. To remove this warning, annotate your test class with @Config(manifest=Config.NONE).

No such manifest file: .\AndroidManifest.xml

I've tried these solutions that failed:

@Config (manifest = Config.DEFAULT_MANIFEST_NAME)

@Config(manifest = Config.NONE, constants = BuildConfig.class, sdk = 26)

@Config( constants = BuildConfig.class, manifest="src/main/AndroidManifest.xml", sdk = 26 )

And the other error during execution is:

android.content.res.Resources$NotFoundException: Unable to find resource ID #0x7f09001b in packages [android, org.robolectric.default]

...

at

com.example.robertoassad.alltestsmerge.MainActivity.onCreate(MainActivity.java:52)

This line that have the error is the following code:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

Specifically in: setContentView(R.layout.activity_main);

For me I didn't see sense in this issue ...

DETAILS:

  • The test class is on the folder: app\src\test\java\com\example\robertoassad

  • The test is: @RunWith( RobolectricTestRunner.class) public class Roboletric { @Test public void clickingLogin_shouldStartLoginActivity() { MainActivity activity = Robolectric.setupActivity(MainActivity.class); activity.findViewById(R.id.button2).performClick();

            Intent expectedIntent = new Intent(activity, SecondActivity.class);
            Intent actual = ShadowApplication.getInstance().getNextStartedActivity();
            assertEquals(expectedIntent.getComponent(), actual.getComponent());
         }
    

    }

回答1:

I had a similar problem to the one you face. The post by jongerrish on the Robolectric GitHub Issue about this resolved the problem for me.

The aspect of the answer that worked for me was to add a testOptions block in my module's build.gradle file:

testOptions {
    unitTests {
        includeAndroidResources = true
    }
}

After adding this block my tests were able to run and access String resources.



回答2:

This problem bug me for some time, and here is my note in my test code.

About manifest location

With Gradle build system, Robolectric looks for AndroidManifest.xml in the following order.

  • Java resource folder

  • build/intermediates/manifests/[full or fast-start]/[build-type]

So it is a common mistake to specify the location of AndroidManifest.xml according to source code folder organization (e.g. src/main/AndroidManifest.xml) . The specified AndroidManifest.xml location affect how Robolectric look for merged resources as well. So if some resource is not found in test, it is probably due to incorrect setting of AndroidManifest.xml location.

That said, the Android Gradle plugin merge the AndroidManifest.xml and put the result under the above mentioned intermediates directory. So the content of src/main/AndroidManifest.xml affect the test result.

So if you want to specify manifest option in @Config, just use @Config(manifest=“AndroidManifest.xml”) should probably be fine. If you want to use an alternate AndroidManifest.xml, put it in Java resources folder, and specify @Config according to the relative path in resources folder.



回答3:

I was also facing same problem while testing my library module from app. Now my Receievers and Service are in my library, so to test those , i had to implement custom Test Class, so Roboelectric can point to my library manifest and not the app manifest :

import android.os.Build;
import org.junit.runners.model.InitializationError;
import org.robolectric.manifest.AndroidManifest;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.res.Fs;

import java.io.File;
import java.io.IOException;

public class RobolectricGradleTestRunner extends RobolectricTestRunner {
    private static final String PROJECT_DIR =
            "C:/MyProject/";


    private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC =
            Build.VERSION_CODES.JELLY_BEAN_MR2;

    public RobolectricGradleTestRunner(final Class<?> testClass) throws Exception {
        super(testClass);
    }

    private static AndroidManifest getAndroidManifest() {

        String manifestPath = PROJECT_DIR+"/src/main/AndroidManifest.xml";
        String resPath = PROJECT_DIR+"/src/main/res";
        String assetPath = PROJECT_DIR+"/src/main/assets";

        System.out.print("manifest path: "+manifestPath);
        System.out.print("resPath path: "+resPath);
        System.out.print("assetPath path: "+assetPath);

        return new AndroidManifest(
                Fs.fileFromPath(manifestPath), Fs.fileFromPath(resPath), Fs.fileFromPath(assetPath)) {
            @Override public int getTargetSdkVersion() {
                return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC;
            }
        };
    }

    private static String getProjectDirectory() {
        String path = "";
        try {
            File file = new File("..");
            path = file.getCanonicalPath();
            path = path + "/app/";
        } catch (IOException ex) {}
        return path;
    }

    @Override public AndroidManifest getAppManifest(Config config) {
        return getAndroidManifest();
    }
}

and use it in your test class like :

@RunWith(RobolectricGradleTestRunner.class)
public class MyClassChangeTest {
}