问题描述
当我尝试用mock创建一个 AppCompatImageView
时,我收到一个 NullPointerException
上下文
在测试中。 此测试通过
import android.content.Context;
import android.widget.ImageView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static junit.framework.Assert.assertNotNull;
@RunWith(MockitoJUnitRunner.class)
public class ParallaxViewTest {
@Mock
上下文mContext;
@Before
public void setup(){
MockitoAnnotations.initMocks(this);
}
@Test
public void initWithContext()throws Exception {
assertNotNull(mContext);
ImageView imageView = new ImageView(mContext);
// AppCompatImageView imageView = new AppCompatImageView(mContext);
}
}
此测试不通过: strong>
import android.content.Context;
import android.support.v7.widget.AppCompatImageView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static junit.framework.Assert.assertNotNull;
@RunWith(MockitoJUnitRunner.class)
public class ParallaxViewTest {
@Mock
上下文mContext;
@Before
public void setup(){
MockitoAnnotations.initMocks(this);
}
@Test
public void initWithContext()throws Exception {
assertNotNull(mContext);
// ImageView imageView = new ImageView(mContext);
AppCompatImageView imageView = new AppCompatImageView(mContext);
}
}
这是崩溃报告: / strong>
java.lang.NullPointerException
at android.support.v7.widget.ResourcesWrapper。< init> ;(ResourcesWrapper.java:46)
at android.support.v7.widget.TintResources。< init>(TintResources.java:34)
at android.support.v7.widget.TintContextWrapper。< ; init>(TintContextWrapper.java:100)
at android.support.v7.widget.TintContextWrapper.wrap(TintContextWrapper.java:68)
at android.support.v7.widget.AppCompatImageView。< init>(AppCompatImageView.java:60)
at android.support.v7.widget.AppCompatImageView。< init>(AppCompatImageView.java:56)
at android.support.v7.widget.AppCompatImageView。 < init>(AppCompatImageView.java:52)
at example.views.ParallaxViewTest.initWithContext(ParallaxViewTest.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
在sun.refle ct.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在java.lang.reflect.Method.invoke(Method.java: 497)
在org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:50)
在org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12 )
在org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
在org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
在org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
在org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
在org.junit.runners.ParentRu nner $ 3.run(ParentRunner.java:290)
在org.junit.runners.ParentRunner $ 1.schedule(ParentRunner.java:71)
在org.junit.runners.ParentRunner.runChildren(ParentRunner。 java:288)
在org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:58)
在org.junit.runners.ParentRunner $ 2.evaluate(ParentRunner.java:268)
在org.junit.runners.ParentRunner.run(ParentRunner.java:363)
在org.mockito.internal.runners.DefaultInternalRunner $ 1.run(DefaultInternalRunner.java:68)
在org。在默认情况下MockitoJUnitRunner.run(MockitoJUnitRunner.java:161)
在org.junit.runner.JUnitCore.run(JUnitCore.java:137)
在com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java: 117)
在com.intellij.junit4.JUnit4IdeaTestRunner.startRunn erWithArgs(JUnit4IdeaTestRunner.java:42)
在com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
在com.intellij.rt.execution.junit.JUnitStarter。 main(JUnitStarter.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun。 reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在java.lang.reflect.Method.invoke(Method.java:497)
在com.intellij.rt.execution.application.AppMain。主要(AppMain.java:147)
这些库: p>
testCompile'junit:junit:4.12'
testCompile'org.mockito:mockito-core:2.7.18'
我该如何解决? >
编辑
我怎么可以得到一个moc
此测试不通过:
@Test
public void initWithContext()throws Exception {
assertNotNull(mContext); // PASS
assertNotNull(mContext.getResources()); // Do not PASS
// ImageView imageView = new ImageView(mContext);
// AppCompatImageView imageView = new AppCompatImageView(mContext);
}
堆栈跟踪中列出的类的代码(),你会发现:
public ResourcesWrapper (资源资源){
super(resources.getAssets(),resources.getDisplayMetrics(),
而那行46是带有super()的那一行。
进一步研究你的堆栈跟踪中的类,你可以进行交叉:
private TintContextWrapper(@NonNull final Context base){
super(base);
...
mResources =新的VectorEnabledTintResources(this,base.getResources());
所以,长篇小说,是的,你正在向非空模拟对象提供新的AppCompatImageView()
在您的代码。但是,您正在调用的代码正在调用嘲笑对象的方法。当然,这就是为什么你首先创造了一个模拟的原因。但猜猜是什么默认情况下,嘲笑框架将返回任何方法调用的 null 。
换句话说:您必须了解强>电话会发生在那个模拟上;所以你可以准备模拟来返回一个非null !
确切地说:我不是说从TintContextWrapper ()导致NPE;我主要是说:当你把一个嘲讽的对象放到其他的代码中时,你必须使用准备来模拟那些会发生的方法调用的合理结果。这很可能意味着你必须创造更多的嘲笑;所以像 mockedContext.getResources()
这样的东西就会返回一个非null 结果。
换句话说:你必须
- 识别在那个模拟对象上发生的那些呼叫
- 那么你必须确保这些调用将返回非空(例如,再次返回嘲笑的对象)。
除此之外:更可能的是,真正的答案是使用 Android特定的嘲笑框架。准备你的嘲讽让他们做正确的事情很容易变成很多工作。
可能简单的答案是使用 深桩>从mockito,通过简单地写
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
但是您需要阅读/尝试;我没有使用自己。
鉴于您最新的内容:您需要配置您的模拟,例如
when(context.getResources())。thenReturn(someOtherMock);例如
那就是整个嘲笑点:你可以控制调用方法时会发生什么!
I am receiving a NullPointerException
when I try to create an AppCompatImageView
with a mock Context
in a test. Doing the same with a normal ImageView
works.
This test pass:
import android.content.Context;
import android.widget.ImageView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static junit.framework.Assert.assertNotNull;
@RunWith(MockitoJUnitRunner.class)
public class ParallaxViewTest {
@Mock
Context mContext;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void initWithContext() throws Exception {
assertNotNull(mContext);
ImageView imageView = new ImageView(mContext);
// AppCompatImageView imageView = new AppCompatImageView(mContext);
}
}
This test DOES NOT pass:
import android.content.Context;
import android.support.v7.widget.AppCompatImageView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static junit.framework.Assert.assertNotNull;
@RunWith(MockitoJUnitRunner.class)
public class ParallaxViewTest {
@Mock
Context mContext;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void initWithContext() throws Exception {
assertNotNull(mContext);
// ImageView imageView = new ImageView(mContext);
AppCompatImageView imageView = new AppCompatImageView(mContext);
}
}
And this is the crash report:
java.lang.NullPointerException
at android.support.v7.widget.ResourcesWrapper.<init>(ResourcesWrapper.java:46)
at android.support.v7.widget.TintResources.<init>(TintResources.java:34)
at android.support.v7.widget.TintContextWrapper.<init>(TintContextWrapper.java:100)
at android.support.v7.widget.TintContextWrapper.wrap(TintContextWrapper.java:68)
at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:60)
at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:56)
at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:52)
at example.views.ParallaxViewTest.initWithContext(ParallaxViewTest.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
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.DefaultInternalRunner$1.run(DefaultInternalRunner.java:68)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:74)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:161)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Here the libraries:
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.7.18'
How can I solve this?
EDIT
How can I get a mock Context
with resources?
This test DOES NOT pass:
@Test
public void initWithContext() throws Exception {
assertNotNull(mContext); // PASS
assertNotNull(mContext.getResources()); // DO NOT PASS
// ImageView imageView = new ImageView(mContext);
// AppCompatImageView imageView = new AppCompatImageView(mContext);
}
When you turn to the source code of the class listed in the stack trace (ResourcesWrapper), you find:
public ResourcesWrapper(Resources resources) {
super(resources.getAssets(), resources.getDisplayMetrics(),
And that line 46 is the one with super().
Further looking into the classes in your stack trace, you could come accross:
private TintContextWrapper(@NonNull final Context base) {
super(base);
...
mResources = new VectorEnabledTintResources(this, base.getResources());
So, long story short, yes, you are providing a non null mock object to new AppCompatImageView()
in your code. But then the code you are calling is calling methods on that mocked object. Sure, that is why you created a mock in the first place. But guess what; by default, the mocking framework will return null for any method call.
In other words: you have to understand which calls will happen on that mock; so that you can prepare the mock to return something non null too!
To be precise: I am not saying that exactly that line from TintContextWrapper() causes this NPE; I am mainly saying: when you give a mocked object into other code, you have to prepare that mock to return reasonable results on those method calls that will happen. That could very well mean that you have to create more mocks; so that something like mockedContext.getResources()
does return a non-null result.
In other words: you have to
- identify those calls that happen on that mock object
- then you have to make sure that those calls will return non-null (for example by returning mocked objects again).
Beyond that: more likely, the real answer is to use Android specific mocking frameworks. Preparing your mocks to get them "do the right thing" could easily turn into a lot of work.
Maybe the simple answer is to use the deep stubbing from mockito, by simply writing
@Mock (answer = Answers.RETURNS_DEEP_STUBS)
But you need to read/try that; I haven't used that myself.
And given your latest: you need to configure your mock, like
when(context.getResources()).thenReturn(someOtherMock);
for example! That is the whole point of mocks: you can control what happens when methods are called!
这篇关于NullPointerException创建具有模拟上下文的AppCompatImageView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!