How to access files from assets folder during tests execution?

后端 未结 8 2081
旧时难觅i
旧时难觅i 2021-02-01 20:25

How to access files from assets folder during unit tests execution? My project is build using Gradle, I use Robolectric to run tests. It seems like gradle is being recognizing t

相关标签:
8条回答
  • 2021-02-01 20:50

    If you are using Kotlin, you can have something like this:

    getInstrumentation().targetContext.assets.open("news.json")
    

    instead of .context, you can simply use targetContext

    0 讨论(0)
  • 2021-02-01 20:51

    Did you try placing the assets folder under main instead of androidTest?

    Also, are you using https://github.com/robolectric/robolectric-gradle-plugin to run your tests?

    0 讨论(0)
  • 2021-02-01 21:00

    When Robolectric versions previous to 4.0 we need to take in count that:

    By default, Robolectric will assume that your resources and assets are located in directories named res and assets, respectively. These paths are assumed to be relative to the directory where the manifest is located. You can change these values by adding the resourceDir and assetDir options to the @Config annotation.

    See the official docs

    0 讨论(0)
  • 2021-02-01 21:01

    With the latest Android Instrumentation Test, you can just use this:

    InstrumentationRegistry.getContext().getAssets().open(filePath);
    
    0 讨论(0)
  • 2021-02-01 21:07

    Basically you have to use Context to read assets. You can not load assets with ClassLoader since it is not in a classpath. I am not sure how you run Robolectric test cases. Here are how I can achieve in both Android studio and gralde command.

    I added separate app-unit-test module to run Robolectric test cases in app project. With proper build configuration and custom RobolectricTestRunner, following test case will pass.

    @Config
    @RunWith(MyRobolectricTestRunner.class)
    public class ReadAssetsTest {
    
        @Test
        public void test_ToReadAssetsFileInAndroidTestContext() throws IOException {
    
            ShadowApplication application = Robolectric.getShadowApplication();
            Assert.assertNotNull(application);
            InputStream input = application.getAssets().open("b.xml");
            Assert.assertNotNull(input);
        }
    
    }
    

    app-unit-test/build.gradle

    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:0.14.1'
        }
    }
    
    apply plugin: 'java'
    evaluationDependsOn(':app')
    
    sourceCompatibility = JavaVersion.VERSION_1_7
    targetCompatibility = JavaVersion.VERSION_1_7
    
    repositories {
        maven { url "$System.env.ANDROID_HOME/extras/android/m2repository" } // Fix 'com.android.support:*' package not found issue
        mavenLocal()
        mavenCentral()
        jcenter()
    }
    
    dependencies {
        testCompile 'junit:junit:4.8.2'
        testCompile('org.robolectric:robolectric:2.4') {
            exclude module: 'classworlds'
            exclude module: 'commons-logging'
            exclude module: 'httpclient'
            exclude module: 'maven-artifact'
            exclude module: 'maven-artifact-manager'
            exclude module: 'maven-error-diagnostics'
            exclude module: 'maven-model'
            exclude module: 'maven-project'
            exclude module: 'maven-settings'
            exclude module: 'plexus-container-default'
            exclude module: 'plexus-interpolation'
            exclude module: 'plexus-utils'
            exclude module: 'wagon-file'
            exclude module: 'wagon-http-lightweight'
            exclude module: 'wagon-provider-api'
            exclude group: 'com.android.support', module: 'support-v4'
        }
        testCompile('com.squareup:fest-android:1.0.+') {
            exclude group: 'com.android.support', module: 'support-v4'
        }
        testCompile 'org.mockito:mockito-core:1.10.10'
        def appModule = project(':app')
        testCompile(appModule) {
            exclude group: 'com.google.android'
            exclude module: 'dexmaker-mockito'
        }
        testCompile appModule.android.applicationVariants.toList().first().javaCompile.classpath
        testCompile appModule.android.applicationVariants.toList().first().javaCompile.outputs.files
        testCompile 'com.google.android:android:4.1.1.4'
        /* FIXME : prevent Stub! error
            testCompile files(appModule.plugins.findPlugin("com.android.application").getBootClasspath())
            */
        compile project(':app')
    }
    

    Add custom RobolectricTestRunner to adjust file paths. Look at the assets path.

    public class MyRobolectricTestRunner extends RobolectricTestRunner {
    
        private static final String APP_MODULE_NAME = "app";
    
        /**
         * Creates a runner to run {@code testClass}. Looks in your working directory for your AndroidManifest.xml file
         * and res directory by default. Use the {@link org.robolectric.annotation.Config} annotation to configure.
         *
         * @param testClass the test class to be run
         * @throws org.junit.runners.model.InitializationError if junit says so
         */
        public MyRobolectricTestRunner(Class<?> testClass) throws InitializationError {
            super(testClass);
            System.out.println("testclass="+testClass);
        }
    
        @Override
        protected AndroidManifest getAppManifest(Config config) {
    
            String userDir = System.getProperty("user.dir", "./");
            File current = new File(userDir);
            String prefix;
            if (new File(current, APP_MODULE_NAME).exists()) {
                System.out.println("Probably running on AndroidStudio");
                prefix = "./" + APP_MODULE_NAME;
            }
            else if (new File(current.getParentFile(), APP_MODULE_NAME).exists()) {
                System.out.println("Probably running on Console");
                prefix = "../" + APP_MODULE_NAME;
            }
            else {
                throw new IllegalStateException("Could not find app module, app module should be \"app\" directory in the project.");
            }
            System.setProperty("android.manifest", prefix + "/src/main/AndroidManifest.xml");
            System.setProperty("android.resources", prefix + "/src/main/res");
            System.setProperty("android.assets", prefix + "/src/androidTest/assets");
    
            return super.getAppManifest(config);
        }
    
    }
    

    I followed this blog to do it.

    • http://blog.blundellapps.com/android-gradle-app-with-robolectric-junit-tests/
    • http://blog.blundellapps.com/how-to-run-robolectric-junit-tests-in-android-studio/

    Full example codes are here.

    0 讨论(0)
  • 2021-02-01 21:07

    I've just got stuck with the same issue and here is how it works for me.

    I put test files to src/test/resources folder instead of assets folder.

    Then I get these files as stream in following way

    private InputStream openFile(String filename) throws IOException {
           return getClass().getClassLoader().getResourceAsStream(filename);
    }
    

    filename is the relative path to the file inside resources folder.

    That's it. I've found solution at Robolectric github

    0 讨论(0)
提交回复
热议问题