Использование нескольких папок res с Robolectric

Моя текущая конфигурация Gradle имеет несколько (объединенных) res-папок:

sourceSets {
    androidTest {
        setRoot('src/test')
    }
    main {
        res.srcDirs =
            [
                'src/main/res/features/registration',
                'src/main/res/features/login',
                'src/main/res'
            ]
    }
}

Но Robolectric позволяет мне настраивать один каталог с помощью AndroidManifest:

public class RobolectricGradleTestRunner extends RobolectricTestRunner {
    private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC = 18;

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

    @Override
    protected AndroidManifest getAppManifest(Config config) {
        String manifestProperty = "../app/src/main/AndroidManifest.xml";
        String resProperty = "../app/src/main/res";

        return new AndroidManifest(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty)) {
            @Override
            public int getTargetSdkVersion() {
                return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC;
            }
        };
    }
}

В этом случае тесты не работают. Можно ли настроить robolectric для отображения моего файла Gradle?

Ответ 1

Хорошо, это самый простой способ сделать это. Вам нужно будет расширить RobolectricTestRunner getAppManifest и createAppResourceLoader.

В getAppManifest вам просто нужно будет сохранить манифест в поле, скажем mDefaultManifest.

В createAppResourceLoader вам нужно будет добавить нужные ресурсы.

/**
 * TODO: Watch OUT this is copied from RobolectricTestRunner in Robolectric-2.4 keep it up to date!
 */
@Override
protected ResourceLoader createAppResourceLoader(ResourceLoader systemResourceLoader, AndroidManifest appManifest) {
    List<PackageResourceLoader> appAndLibraryResourceLoaders = new ArrayList<PackageResourceLoader>();
    for (ResourcePath resourcePath : appManifest.getIncludedResourcePaths()) {
        appAndLibraryResourceLoaders.add(createResourceLoader(resourcePath));
    }

        /* BEGIN EDIT */
        if(mDefaultManifest != null) {
            ResourcePath rpInjected = new ResourcePath(mDefaultManifest.getRClass(), mDefaultManifest.getPackageName(), Fs.fileFromPath("../app/src/main/res/features/registration"), mDefaultManifest.getAssetsDirectory());
            appAndLibraryResourceLoaders.add(createResourceLoader(rpInjected));
            rpInjected = new ResourcePath(mDefaultManifest.getRClass(), mDefaultManifest.getPackageName(), Fs.fileFromPath("../app/src/main/res/features/login"), mDefaultManifest.getAssetsDirectory());
            appAndLibraryResourceLoaders.add(createResourceLoader(rpInjected));
        }
        /* END EDIT */

    OverlayResourceLoader overlayResourceLoader = new OverlayResourceLoader(appManifest.getPackageName(), appAndLibraryResourceLoaders);

    Map<String, ResourceLoader> resourceLoaders = new HashMap<String, ResourceLoader>();
    resourceLoaders.put("android", systemResourceLoader);
    resourceLoaders.put(appManifest.getPackageName(), overlayResourceLoader);
    return new RoutingResourceLoader(resourceLoaders);
}

Не забудьте добавить @RunWith(YourTestRunner.class) в тестовые классы.

Ответ 2

Другое решение похожее на Luca's:

public class MyTestRunner extends RobolectricTestRunner {
    ...
    @Override
    protected AndroidManifest getAppManifest(Config config) {
        String appRoot = "./src/main/";
        String manifestPath = appRoot + "AndroidManifest.xml";
        String resDir = appRoot + "res";
        String assetsDir = appRoot + "assets";

        return new AndroidManifest(Fs.fileFromPath(manifestPath), Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir)) {
            @Override
            public List<ResourcePath> getIncludedResourcePaths() {
                List<ResourcePath> paths = super.getIncludedResourcePaths();
                paths.add(new ResourcePath(getRClass(), getPackageName(), Fs.fileFromPath("../app/src/main/res/features/registration"), getAssetsDirectory()));
                paths.add(new ResourcePath(getRClass(), getPackageName(), Fs.fileFromPath("../app/src/main/res/features/login"), getAssetsDirectory()));
                return paths;
            }
        };
    }
}

Не забывайте комментировать ваши тесты с помощью @RunWith(MyTestRunner.class)