模拟 Android AssetManager

7

我有一段代码,它接受Context并将此Context传递给一个私有方法。这个私有方法调用getAssets().open()来读取我应用程序中assets文件夹中存在的文件。

public void methodA(Context ctx) throws IOException{
     // do some stuff here...
     Object data[] = getFileContents(ctx);
     // use the data[] returned here...

}

private Object[] getFileContents(Context ctx) throws IOException{
     Object[] data;
     BufferedInputStream is = new BufferedInputStream(context.getAssets().open("test.txt"));
     // parse file and create array of Objects[]
     return data[];
}

我正在使用Mockito编写单元测试,以测试methodA()方法,以便在测试用例中传递垃圾数据或引发异常。

问题在于,我无法在Android中模拟AssetManager类(它是Final的)。

我尝试使用InstrumentationTestCase来注入真实和测试上下文,但这仅适用于一些场景。如何控制BufferedInputStream,以便我可以提供任何所需输入(使用模拟或其他方式)?

3个回答

11

我曾经也遇到过同样的问题。以下是我在不使用Instrumentation测试的情况下,如何从我的单元测试程序中访问配置文件的方法。(我使用Android Studio 2.1)

单元测试的代码:

public class ParametersTest {

    Parameters parameters = null;

    @Mock
    Context context;
    @Mock
    AssetManager assetManager;
    @Mock
    InputStream inputStream;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);//create all @Mock objetcs
        doReturn(assetManager).when(context).getAssets();
        //parametersandroid.xml is located in test/resources directory
        //parametersandroid.xml does not refer to a DTD file configuration.dtd
        //get the full path name of the file
        URL resource = ParametersTest.class.getClassLoader().getResource("parametersandroid.xml");
        // to be used  MyClass
        // inside the method I want to be tested there is this statement :
        // InputStream inputStream = this.assetManager.open(xmlFile);
        InputStream inputStream=new FileInputStream(resource.getPath());
        doReturn(inputStream).when(assetManager).open(anyString());
       // AssetManager assetManager = context.getAssets();
       // parameters = new Parameters(assetManager, resource.getPath());
        parameters = new Parameters(context, resource.getPath());

    }
    @Test
    public void testExtract() throws Exception {
       assertEquals(parameters.extract("//database/index[@name='TeamNameIdx']/create").replaceAll("[^a-z,A-Z,;,.,?,']", ""),"createindexTeamNameIdxonTeamEntnameasc;");
    }
}

需要测试的类的代码:

public class Parameters extends fr.acnice.valade.eric.gemara.utilities.Parameters {
    private AssetManager assetManager = null;

    public Parameters(Context context, String xmlFile) {
        super(xmlFile);
        this.assetManager = context.getAssets();
    }
    @Override
    public String extract(String request) throws XPathExpressionException,
            Exception {
        InputStream inputStream = this.assetManager.open(super.xmlFile);
        String result = (String) xPath.evaluate(request, new InputSource(inputStream),
                XPathConstants.STRING);
        if (result.isEmpty()) {
            throw new Exception(
                    "Xpath result empty !!! check configuration file");
        }
        return result;
    }

}

2

通过调用以下代码尝试检索context

Context context = InstrumentationRegistry.getTargetContext();
BufferedInputStream is = new BufferedInputStream(context.getAssets().open("test.txt"));

0
ProviderTestCase2的情况下,调用context.getResources().getAssets()而不是context.getAssets()可以解决我的问题。否则,您需要使用ApplicationProvider.getApplicationContext<Context>()来获取具有文件访问权限的Context实例(在测试中)。 似乎ProviderTestCase2使用RenamingDelegatingContext将文件方法转发到未存根的方法,但由于某种原因,context.getAssets()被省略了。我对新测试工具还不够深入,无法确定其他类型的测试用例是否会发生相同的情况。
AndroidX文档很乱,我正在阅读框架源代码以找出自己在做什么。希望这能帮助到某些人。

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