Android上的Mockito、Context.getString(id)和NullPointerException

Android上的Mockito、Context.getString(id)和NullPointerException,android,unit-testing,testing,mockito,Android,Unit Testing,Testing,Mockito,我刚刚开始学习Mockito测试框架,我遵循以下官方教程: 代码是: private static final String FAKE_STRING = "HELLO WORLD"; @Mock Context mMockContext; @Test public void readStringFromContext_LocalizedString() { // Given a mocked Context injected into the object under test...

我刚刚开始学习Mockito测试框架,我遵循以下官方教程:

代码是:

private static final String FAKE_STRING = "HELLO WORLD";

@Mock
Context mMockContext;

@Test
public void readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    when(mMockContext.getString(R.string.hello_world))
            .thenReturn(FAKE_STRING);
    ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext);

    // ...when the string is returned from the object under test...
    String result = myObjectUnderTest.getHelloWorldString();

    // ...then the result should be the expected one.
    assertThat(result, is(FAKE_STRING));
}
我在测试中编写了以下类:

public class ClassUnderTest {

private Context context;

public ClassUnderTest(Context context)
{
    this.context=context;
}

public String getHelloWorldString()
{
    return context.getString(R.string.hello_world);
}
}

运行之后,我得到了NullPointerException:

    java.lang.NullPointerException
at android.content.Context.getHelloWorldString(Context.java:293)
at com.darekk.draggablelistview.unit_tests.MockitoTest.readStringFromContext_LocalizedString(MockitoTest.java:46)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1619)
当我用自己的类替换android上下文时,它就可以工作了

平台:IntelliJ IDEA社区版15.0.6


非常感谢您的帮助。

此代码应该是您测试的第一行:

doReturn("Sample Hello world string")
            .when(mMockContext)
            .getString(any(Integer.class));

需要一个方法存根

看起来您使用的是来自的精确代码。显然,他们发布了一个不完整的例子。。将此方法添加到测试中:

@Before
public void setup(){
   MockitoAnnotations.initMocks(this);
}
为了进一步参考,checkout

Context.getString()是最后一个方法,因此默认情况下不能使用Mockito模拟它。 要启用对最终方法的模拟,您需要Mockito v2,并按照此处的说明进行操作

src/test/resources/mockito extensions/org.mockito.plugins.MockMaker
中创建一个文件,其中包含一行:

mock-maker-inline

完成此操作后,可以在(mMockContext.getString(R.string.string_name))时模拟getString()
,然后返回(“模拟字符串”)

在build.gradle文件中添加以下依赖项

testImplementation "org.powermock:powermock:1.6.5"

然后运行上面的代码,它就会开始工作。

Hmm,我应该把它放在getHelloWorldString()方法中吗?到底在哪里?真奇怪。我认为只有Context.getString(…)应该被存根。编辑了我的答案。不需要修改测试中的类。我有这样一个:when(mMockContext.getString(R.string.hello\u world)),然后return(FAKE\u string);我尝试了您的解决方案,但是any(Integer.class)无法解析,因此我改用anyInt()并得到另一个错误:org.mockito.exceptions.misusing.InvalidUseOfMatchersException:参数匹配器的使用无效!应为0个匹配者,1个已录制:您的解决方案与海报在(mMockContext.getString(R.string.hello_world))时已有的
没有差异。然后返回(FAKE_string)这是不正确的。根据Android文档:“在运行时,[本地单元]测试是针对Android.jar的一个修改版本执行的,其中所有最终修改器都已剥离。这允许您使用流行的模拟库,如Mockito。”请参阅