btn.performClick() 无法模拟对象,但 Activity 可以调用函数
btn.performClick() Unable mock Object,but Activity call the function is able
我尝试使用 Mockito 测试按钮功能。代码包括Layout/SampleActivity/UnitTest 主要内容:
布局文件定义:
android:text="testbtnmock"
android:id="@+id/btn_testbtnmock"
android:onClick="testBtnMock"
SampleActivity 文件定义
public void testBtnMock(View view) {
System.out.println("value:"+getInt());
}
public int getInt(){
return 0;
}
单元测试文件定义
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class SampleActivityTest {
private SampleActivity sampleActivity;
private Button testBtnMock;
@Before
public void setUp() {
ShadowLog.stream = System.out;
}
@Test
public void testBtnMock() {
sampleActivity = Robolectric.setupActivity(SampleActivity.class);
SampleActivity spySampleActivity = spy(sampleActivity);
when(spySampleActivity.getInt()).thenReturn(100);
//spySampleActivity.testBtnMock(mock(View.class)); //it is working , print 100
testBtnMock = (Button) sampleActivity.findViewById(R.id.btn_testbtnmock);
testBtnMock.performClick(); //it is not work , print 0 ,mock invalid
}
}
我的问题是:
- 为什么用
spySampleActivity.testBtnMock(mock(View.class));
来触发testBtnMock(View v)
的功能。它正在工作并打印 100.
- 但使用
testBtnMock.performClick();
不起作用并打印 0。为什么?怎么解决?
这很容易解释。
XML 属性将用于通过反射调用方法 (How does the android Xml attribute android:onClick="..." work behind the scenes?)。
因此,通过一些简化,将使用来自按钮的上下文并通过反射调用方法。按钮在 inflation 期间获取上下文,它是对不监视 activity 的引用。这就是为什么在您的测试中调用真实方法的原因。
当您通过对 spy 的引用调用该方法时 activity 它有效。
如何修复:
- 提取一个class负责提供整数
- 模拟它并在测试中注入
类似于:
public class IntegerProvider {
public int getInt(){
return 0;
}
}
public class SampleActivity {
IntegerProvider intProvider;
public void testBtnMock(View view) {
System.out.println("value:" + intProvider.getInt());
}
}
@Test
public void testBtnMock() {
sampleActivity = Robolectric.setupActivity(SampleActivity.class);
IntegerProvider providerMock = mock(IntegerProvider.class);
when(providerMock.getInt()).thenReturn(100);
sampleActivity.intProvider = providerMock;
testBtnMock = (Button) sampleActivity.findViewById(R.id.btn_testbtnmock);
testBtnMock.performClick();
}
我尝试使用 Mockito 测试按钮功能。代码包括Layout/SampleActivity/UnitTest 主要内容:
布局文件定义:
android:text="testbtnmock"
android:id="@+id/btn_testbtnmock"
android:onClick="testBtnMock"
SampleActivity 文件定义
public void testBtnMock(View view) {
System.out.println("value:"+getInt());
}
public int getInt(){
return 0;
}
单元测试文件定义
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class SampleActivityTest {
private SampleActivity sampleActivity;
private Button testBtnMock;
@Before
public void setUp() {
ShadowLog.stream = System.out;
}
@Test
public void testBtnMock() {
sampleActivity = Robolectric.setupActivity(SampleActivity.class);
SampleActivity spySampleActivity = spy(sampleActivity);
when(spySampleActivity.getInt()).thenReturn(100);
//spySampleActivity.testBtnMock(mock(View.class)); //it is working , print 100
testBtnMock = (Button) sampleActivity.findViewById(R.id.btn_testbtnmock);
testBtnMock.performClick(); //it is not work , print 0 ,mock invalid
}
}
我的问题是:
- 为什么用
spySampleActivity.testBtnMock(mock(View.class));
来触发testBtnMock(View v)
的功能。它正在工作并打印 100. - 但使用
testBtnMock.performClick();
不起作用并打印 0。为什么?怎么解决?
这很容易解释。
XML 属性将用于通过反射调用方法 (How does the android Xml attribute android:onClick="..." work behind the scenes?)。
因此,通过一些简化,将使用来自按钮的上下文并通过反射调用方法。按钮在 inflation 期间获取上下文,它是对不监视 activity 的引用。这就是为什么在您的测试中调用真实方法的原因。
当您通过对 spy 的引用调用该方法时 activity 它有效。
如何修复:
- 提取一个class负责提供整数
- 模拟它并在测试中注入
类似于:
public class IntegerProvider {
public int getInt(){
return 0;
}
}
public class SampleActivity {
IntegerProvider intProvider;
public void testBtnMock(View view) {
System.out.println("value:" + intProvider.getInt());
}
}
@Test
public void testBtnMock() {
sampleActivity = Robolectric.setupActivity(SampleActivity.class);
IntegerProvider providerMock = mock(IntegerProvider.class);
when(providerMock.getInt()).thenReturn(100);
sampleActivity.intProvider = providerMock;
testBtnMock = (Button) sampleActivity.findViewById(R.id.btn_testbtnmock);
testBtnMock.performClick();
}