Android junit4打开getResources()。使用mockito的openRawResource运行nullpointer
我正在创建一个Android junit4打开getResources()。使用mockito的openRawResource运行nullpointer,android,mockito,junit4,Android,Mockito,Junit4,我正在创建一个junit4单元测试,以测试是否打开原始目录中包含的文件 但是,每次代码运行时,我都可以从openrawsource中找到一个空指针 这就是我要测试的功能。在实际设备上运行时,此功能有效。但不是在单元测试中 android studio 2.1. preview 4 这是我的测试用例 public String getNewsFeed(Context mContext) { InputStream inputStream = mContext.getResources()
junit4单元测试
,以测试是否打开原始目录中包含的文件
但是,每次代码运行时,我都可以从openrawsource
中找到一个空指针
这就是我要测试的功能。在实际设备上运行时,此功能有效。但不是在单元测试中
android studio 2.1. preview 4
这是我的测试用例
public String getNewsFeed(Context mContext) {
InputStream inputStream = mContext.getResources().openRawResource(R.raw.news_list); // Null pointer
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
InputStreamReader inputReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferReader = new BufferedReader(inputReader);
int n;
while ((n = bufferReader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
inputStream.close();
}
catch (IOException ioException) {
return "";
}
return writer.toString();
}
非常感谢您的建议,您必须告诉mContext mock在调用getResources()时该怎么做
@RunWith(MockitoJUnitRunner.class)
public class NewsListPresenterTest {
@Mock
private Context mContext;
@Mock
private NewsListPresenter mNewsListPresenter;
@org.junit.Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mNewsListPresenter = new NewsListPresenter(mContext);
}
@org.junit.Test
public void testLoadNewsFeed() throws Exception {
assertNotNull(mNewsListPresenter.getNewsFeed(mContext));
}
}
如果不指定任何内容,mock将返回null
对于您的示例,这意味着您可能还需要一个资源模拟,并在调用openRawResource()时告诉它何时执行/返回。您已经创建了一个模拟
上下文
,因此您必须存根被测方法使用的方法。
在getNewsFeed
中,您正在使用Context::getResources
,因此在调用getNewsFeed
之前的测试中,您应该:
when(mContext.getResources()).thenReturn(some_mock_of_Resources);
问题很清楚
在你的测试中,你也有一些问题。我认为它们没有任何后果,但它们往往表明你正在发现莫基托 你写道:
Resources resoures = ...
when(mContext.getResources()).thenReturn(resources);
用@Mock
注释字段,告诉mockito创建一个NewsListPresenter
的Mock,该类将被测试。(这不是一个大问题,因为您在设置中创建了真实的实例。你可以去看看(即使)
另一点是,您同时使用@RunWith(MockitoJUnitRunner.class)
和
MockitoAnnotations.initMocks(this)
,您可以避免最后一个,因为它是由运行程序调用的。此外,跑步者是一个更好的选择,因为它
我最后的观察是关于你的设计。这可能是一个android约束,但您正在presenter构造函数和getNewsFeed
方法中注入上下文,这看起来很奇怪,可能会导致不一致的情况。我会选择构造函数注入(更面向对象的设计)
另一种简化测试的方法是提取实用程序类中方法的主要部分,并测试不同的分支(空流、空流、有效流、IOException…),而无需模拟上下文和资源:
@Mock
private NewsListPresenter mNewsListPresenter;
请注意,guava提供了一个解决方案。您混淆了Android中的两种单元测试。这对很多人来说并不清楚,所以我会在这里解释
为什么它在设备上工作:因为这是一个仪器化测试。
什么是仪器化测试?在真实设备/模拟器上运行的测试,测试代码位于“src/androidTest”文件夹中
为什么它不能作为本地junit测试工作:因为本地junit测试不是插装测试。本地Junit测试在计算机的JVM上运行,而不是在设备上运行。本地Junit测试不应该包含/使用Android代码,因为真正的Android代码在设备/模拟器上,而不是在计算机的JVM上
我想您想让它作为junit测试运行,以更快地运行它,这就是为什么我想您将测试移动到“src/test”文件夹和上下文中。getResources()引发了NullPointerException
我认为你有两个选择:
用于将此测试作为junit测试运行
重构您的方法,使其不依赖于Android的类
对于选项2,我会这样做。将方法的参数更改为InputStream:
class IOUtils {
static String readFromStream(InputStream inputStream) {
....
}
}
现在,您的方法看不到任何Android代码,您可以将其作为普通junit方法进行测试。然后,您可以将一个伪inputStream传递给您的方法,如下所示:
public String getNewsFeed(InputStream inputStream) {... use inputStream... }
如果您仍然希望通过与您在应用程序中使用的相同的inputStream(我不建议这样做),您仍然可以在测试中使用以下代码:
@Test
public void testLoadNewsFeed() throws Exception {
String fileContents = "line one";
InputStream inputStream = new ByteArrayInputStream(fileContents.getBytes());
assertNotNull(mNewsListPresenter.getNewsFeed(inputStream));
}
您必须将这一行添加到build.gradle文件中:
@Test
public void testLoadNewsFeed() throws Exception {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("raw/news_list");
assertNotNull(mNewsListPresenter.getNewsFeed(inputStream));
}
Android单元测试可能会非常混乱。你可以在我写的博客文章中读到这些概念你能说得更具体些吗。我正在这样做:when(mContext.getResources())。然后return(R.raw.news\u list);但是R.raw.news_列表未被识别。你能给我一些更多的指导吗?如果这是你第一次用mock做单元测试,你可能想按照mockito的一些教程开始。@ant2009当(mContext.getResources())时你在哪里做。然后返回(R.raw.news_list)
?它不在您发布的代码中。@ant2009您不能为mContext.getResources()返回int,您需要返回一个资源实例(或像Yair建议的那样使用)。调用getResources时,我已尝试返回一个模拟资源。但是,我无法使用如此模拟的资源访问字符串或drawables。when(context.getResources()).thenReturn(PowerMockito.mock(Resources.class));String str=context.getResources().getString(R.String.app_name);返回的str值为null。
sourceSets.test.resources.srcDirs += ["src/main"]