如何为Android单元测试提供数据文件

49
我正在使用Android的java.xml.parsers.DocumentBuilder和DocumentBuilderFactory实现从XML文件加载信息的软件开发中。我正在编写对象的单元测试,并需要提供各种XML文件来测试代码。我使用Eclipse并有一个独立的Android测试项目。我找不到一种方法将测试XML放入测试项目中,以使得被测试的代码可以打开这些文件。
  • 如果我把文件放在测试项目的/assets目录下,那么被测试的代码就无法看到它。
  • 如果我把文件放在被测试的代码的/assets目录下,当然它就可以看到这些文件,但现在我的实际系统中被测试的代码会混杂着仅供测试的数据文件。
  • 如果我手动将文件复制到/sdcard/data目录下,那么就可以从被测试的代码中打开它们,但这会干扰我的自动化测试。

如果有任何建议,使得不同的XML测试文件可以存在于测试包中并且对被测试的代码可见,将不胜感激。

以下是我尝试组织单元测试的方式:

public class AppDescLoaderTest extends AndroidTestCase
{
  private static final String SAMPLE_XML = "sample.xml";

  private AppDescLoader       m_appDescLoader;
  private Application         m_app;

  protected void setUp() throws Exception
  {
    super.setUp();
    m_app = new Application();
    //call to system under test to load m_app using
    //a sample xml file
    m_appDescLoader = new AppDescLoader(m_app, SAMPLE_XML, getContext());
  }

  public void testLoad_ShouldPopulateDocument() throws Exception
  {
    m_appDescLoader.load();

  }    
}

原代码无法正常工作,因为SAMPLE_XML文件在测试上下文中,而AndroidTestCase提供了系统测试的上下文,无法从测试包中看到资源文件。

这是根据给出的答案修改后可以正常工作的代码:

public class AppDescLoaderTest extends InstrumentationTestCase
{
   ...
  protected void setUp() throws Exception
  {
    super.setUp();
    m_app = new Application();
    //call to system under test to load m_app using
    //a sample xml file
     m_appDescLoader = new AppDescLoader(m_app, SAMPLE_XML, getInstrumentation().getContext());
  }
3个回答

72

选项1:使用InstrumentationTestCase

假设您在Android项目和测试项目中都有assets文件夹,并且将XML文件放在其中,那么在测试项目下的测试代码中,这将从Android项目的assets文件夹加载xml:

getInstrumentation().getTargetContext().getResources().getAssets().open(testFile);

这将从测试项目的资产文件夹中加载xml:

getInstrumentation().getContext().getResources().getAssets().open(testFile);

选项 2:使用ClassLoader

在测试项目中,如果已将 assets 文件夹添加到项目构建路径中(在 ADT 插件版本 r14 之前自动完成),则可以从 res 或 assets 目录(即项目构建路径下的目录)中加载文件而无需上下文:

String file = "assets/sample.xml";
InputStream in = this.getClass().getClassLoader().getResourceAsStream(file);

1
谢谢。 这个有效,只是我必须先将我的测试案例更改为InstrumentationTestCase。 - Chuck Krutsinger
我修改了我的问题以展示可行的代码。感谢您的帮助。 - Chuck Krutsinger
选择第二个选项加1。在res级别添加了一个assets目录,新代码在Android Studio构建中“只是工作”。无需处理构建路径。 - Anne Gunn
当使用Android Studio时,如果资产不在单独的项目中,则可以将其放在原始应用程序包中(因此请使用目标上下文)。使用Eclipse和独立项目时,应该使用测试项目上下文的可能性更大。 - personne3000
4
那么重要的问题是,我如何在编译发布时不部署它们?为什么安卓不能有一个测试资源文件夹,而不会随着版本发布而被部署? - JPM

9

对于 Android 和 JVM 的单元测试,我使用以下方法:

public final class DataStub {
    private static final String BASE_PATH = resolveBasePath(); // e.g. "./mymodule/src/test/resources/";

    private static String resolveBasePath() {
        final String path = "./mymodule/src/test/resources/";
        if (Arrays.asList(new File("./").list()).contains("mymodule")) {
            return path; // version for call unit tests from Android Studio
        }
        return "../" + path; // version for call unit tests from terminal './gradlew test'
    }

    private DataStub() {
        //no instances
    }

    /**
     * Reads file content and returns string.
     * @throws IOException
     */
    public static String readFile(@Nonnull final String path) throws IOException {
        final StringBuilder sb = new StringBuilder();
        String strLine;
        try (final BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"))) {
            while ((strLine = reader.readLine()) != null) {
                sb.append(strLine);
            }
        } catch (final IOException ignore) {
            //ignore
        }
        return sb.toString();
    }
}

我把所有的原始文件放在下面的路径中:".../project_root/mymodule/src/test/resources/"

你能展示一下访问这些方法时你的测试类是什么样子的吗? - JPM

1

试试这个 Kotlin 代码:

val json = File("src\\main\\assets\\alphabets\\alphabets.json").bufferedReader().use { it.readText() }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接