web-dev-qa-db-ja.com

テストの実行中に資産フォルダーからファイルにアクセスするにはどうすればよいですか?

単体テストの実行中に資産フォルダーからファイルにアクセスするにはどうすればよいですか?私のプロジェクトはGradleを使用してビルドしています。Robolectricを使用してテストを実行しています。 Gradleがassetsを認識しているようです:

enter image description here

これは私がファイルを読むのに苦労している方法です:

public String readFileFromAssets(String fileName) throws IOException {
    InputStream stream = getClass().getClassLoader().getResourceAsStream("assets/" + fileName);
    Preconditions.checkNotNull(stream, "Stream is null");
    BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
    return IOUtils.toString(reader);
}

ただし、streamは常にnullです。私はさまざまな方法で試しました。つまり、さまざまなアプローチを使用してファイルへのパスを定義しました。

事前にどうもありがとうございました。

19
Eugene

基本的に、アセットを読み取るにはContextを使用する必要があります。 ClassLoaderはクラスパスにないため、アセットをロードできません。 Robolectricテストケースの実行方法がわかりません。 Android studioとgraldeコマンドの両方でどのように達成できるかを示します。

アプリプロジェクトでRobolectricテストケースを実行するために、個別のapp-unit-testモジュールを追加しました。適切なビルド構成とカスタムRobolectricTestRunnerを使用すると、次のテストケースに合格します。

@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')
}

カスタムRobolectricTestRunnerを追加して、ファイルパスを調整します。アセットパスを確認します。

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);
    }

}

私はそれをするためにこのブログをフォローしました。

完全なサンプルコードは here です。

10
Chk0nDanger

私は同じ問題で立ち往生しました、そしてそれが私にとってどのように機能するかです。

アセットフォルダではなくsrc/test/resourcesフォルダにテストファイルを配置しました。

次に、これらのファイルを次の方法でストリームとして取得します

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

filenameは、resourcesフォルダー内のファイルへの相対パスです。

それでおしまい。 Robolectric github で解決策を見つけました

11
Andrii Panasiuk

Roboelectric 3.1の更新

    @Test
    public void shouldGetJSONFromAsset() throws Exception{
         Assert.assertNotNull(RuntimeEnvironment.application); //Getting the application context
         InputStream input = RuntimeEnvironment.application.getAssets().open("fileName.xml");// the file name in asset folder
         Assert.assertNotNull(input);
        }

こちらもご覧ください

  1. 2.4から3.0へのアップグレードガイド
  2. .0から3.1へのアップグレードガイド

ドガイド

6
Nicks

最新のAndroid Instrumentation Testを使用すると、これを使用できます:

InstrumentationRegistry.getContext().getAssets().open(filePath);
5
GMsoF

Robolectricは、次の点を考慮する必要があります。

デフォルトでは、Robolectricは、リソースとアセットがそれぞれresとassetsという名前のディレクトリにあると想定します。これらのパスは、マニフェストが配置されているディレクトリからの相対パスと見なされます。これらの値を変更するには、@ ConfigアノテーションにresourceDirおよびassetDirオプションを追加します。

公式 docs を参照してください

0
SHoko

AndroidTestではなくmainの下にアセットフォルダーを配置してみましたか?

また、テストを実行するために https://github.com/robolectric/robolectric-gradle-plugin を使用していますか?

0
kageiit

Kotlinを使用している場合は、次のようにすることができます。

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

.contextの代わりに、単純にtargetContextを使用できます

0
iman kazemayni