我有一个自定义视图,我正在尝试测试不同的屏幕尺寸,但我无法找到有关如何在单元测试中正确模拟显示宽度的文档或示例。
这是我如何尝试使用它的示例:
private CustomTextView customTV;
@Override
protected void setUp() throws Exception {
super.setUp();
DisplayMetrics displayMetrics = mock(DisplayMetrics.class);
displayMetrics.widthPixels = 600;
Resources mockResources = mock(Resources.class);
when(mockResources.getDisplayMetrics()).thenReturn(displayMetrics);
Context mockContext = mock(Context.class);
when(mockContext.getResources()).thenReturn(mockResources);
customTV = new CustomTextView(mockContext);
}
@SmallTest
public void testViewSize() {
Assert.assertEquals("Text size did not scale", 42, customTV.getTextSize());
}
此外,我仅在某些设备上收到错误(上述实现适用于某些屏幕尺寸,但不是全部):
Error in testViewSize:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.content.res.Configuration.isLayoutSizeAtLeast(int)' on a null object reference
at android.view.ViewConfiguration.<init>(ViewConfiguration.java:284)
at android.view.ViewConfiguration.get(ViewConfiguration.java:364)
at android.view.View.<init>(View.java:3781)
at android.view.View.<init>(View.java:3876)
at android.widget.TextView.<init>(TextView.java:655)
at android.widget.TextView.<init>(TextView.java:650)
at android.widget.TextView.<init>(TextView.java:646)
at com.foo.bar.view.CustomTextView.<init>(CustomTextView.java:55)
at com.foo.bar.view.CustomTextView.<init>(CustomTextView.java:45)
at com.foo.bar.view.CustomTextViewTests.setUp(CustomTextViewTests.java:52)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:557)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1874)
我真正想做的是将displayMetrics.widthPixels
的返回值设置为特定数字,但由于它不是方法调用,如 getter 或 setter,所以我不能像在其他模拟对象中使用when
和thenReturn
方法那样覆盖它。
有没有更简单的方法来模拟上下文/资源/显示指标?
为了回答你的问题,你就像你正在做的那样嘲笑它。
DisplayMetrics metrics = mock(DisplayMetrics.class);
metrics.widthPixels = 300;
Resources resources = mock(Resources.class);
when(resources.getDisplayMetrics()).thenReturn(metrics);
Assert.assertEquals(300, resources.getDisplayMetrics().widthPixels);
// ^^ see proof
您发布的错误消息只是建议您需要模拟更多对象。你做得还不够。
java.lang.NullPointerException: 尝试调用虚拟方法 'boolean android.content.res.Configuration
所以也模拟配置对象。
编辑:
如果您使用的是 Robolectric,则使用实际配置显示的代码:
Context context = mock(Context.class);
Resources resources = mock(Resources.class);
when(resources.getConfiguration()).thenReturn(RuntimeEnvironment.application.getResources().getConfiguration());
when(context.getResources()).thenReturn(resources);
最终找到了两种不同的方法来做到这一点,这两种方法最多只使用 Mockito 作为测试库。
选项 1:更新实际Context
private CustomTextView customTV;
@Override
protected void setUp() throws Exception {
super.setUp();
Context context = getContext();
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
Configuration config = context.getResources().getConfiguration();
displayMetrics.widthPixels = 600;
// can optionally set the screen density as well:
displayMetrics.densityDpi = DisplayMetrics.DENSITY_MEDIUM;
config.densityDpi = DisplayMetrics.DENSITY_MEDIUM;
context.getResources().updateConfiguration(config, displayMetrics);
customTV = new CustomTextView(mockContext);
}
@SmallTest
public void testViewSize() {
Assert.assertEquals("Text size did not scale", 42, customTV.getTextSize());
}
选项 2:使用ContextWrapper
+Mockito.spy
private CustomTextView customTV;
@Override
protected void setUp() throws Exception {
super.setUp();
Context context = new ScreenWidthContextWrapper(getContext(), 600);
customTV = new CustomTextView(context);
}
private class ScreenWidthContextWrapper extends ContextWrapper {
private final DisplayMetrics mDisplayMetrics;
private final Resources mSpyResources;
public ScreenWidthContextWrapper(Context realContext, int widthPixels) {
super(realContext);
Resources realResources = realContext.getResources();
mDisplayMetrics = new DisplayMetrics();
mDisplayMetrics.widthPixels = widthPixels;
mDisplayMetrics.setTo(realResources.getDisplayMetrics());
mSpyResources = spy(realResources);
when(mSpyResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
}
@Override
public Resources getResources() {
return mSpyResources;
}
}
@SmallTest
public void testViewSize() {
Assert.assertEquals("Text size did not scale", 42, customTV.getTextSize());
}