如何在执行单元测试期间从assets文件夹访问文件?我的项目是使用Gradle构建的,我使用Robolectric来运行测试。似乎gradle正在识别assets
:
这就是我在努力阅读文件的方式:
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
。我尝试了许多不同的方法,即使用不同的方法定义文件的路径。
非常感谢你。
答案 0 :(得分:10)
基本上,您必须使用Context
来读取资产。您无法使用ClassLoader
加载资源,因为它不在类路径中。我不确定你是如何运行Robolectric测试用例的。以下是我在Android studio和gralde命令中可以实现的方法。
我添加了单独的app-unit-test模块,在app项目中运行Robolectric测试用例。
通过正确的构建配置和自定义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-单元测试/的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。
答案 1 :(得分:9)
我只是遇到了同样的问题,这就是它对我的作用。
我将测试文件放到setTimeout()
文件夹而不是资源文件夹。
然后我按照以下方式将这些文件作为流
src/test/resources
private InputStream openFile(String filename) throws IOException {
return getClass().getClassLoader().getResourceAsStream(filename);
}
是filename
文件夹中文件的相对路径。
那就是它。我在Robolectric github
找到了解决方案答案 2 :(得分:6)
Updating as for 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);
}
See also
de Guide
答案 3 :(得分:5)
使用最新的Android Instrumentation Test,您可以使用:
exec()
答案 4 :(得分:0)
您是否尝试将assets文件夹放在main下而不是androidTest?
另外,您使用https://github.com/robolectric/robolectric-gradle-plugin来运行测试吗?
答案 5 :(得分:0)
在Robolectric中,我们需要计算:
默认情况下,Robolectric将假定您的资源和资产分别位于名为res和asset的目录中。假定这些路径是相对于清单所在目录的。您可以通过将resourceDir和assetDir选项添加到@Config批注中来更改这些值。
见官方docs
答案 6 :(得分:0)
如果您使用的是Kotlin,则可以使用以下内容:
getInstrumentation().targetContext.assets.open("news.json")
代替.context,您只需使用targetContext
答案 7 :(得分:-1)
如果一切正确,那么你需要这样的东西来阅读它:
public String readFileFromAssets(String fileName, Context context) throws IOException {
InputStreamReader stream = new InputStreamReader(context.getAssets().open(fileName));
Preconditions.checkNotNull(stream, "Stream is null");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
return IOUtils.toString(reader);
}
您需要传递Context才能正常工作。
验证您是否已在Gradle中正确配置资产的另一件事是?这只是一个例子:
sourceSets {
main {
java.srcDirs = ['src/main']
// can be configured in different way
assets.srcDirs = ['src/androidTest/assets']
// other things, examples
res.srcDirs = ['res']
manifest.srcFile 'AndroidManifest.xml'
}
}