Telephony 相关类注入问题
常见问题是对象null,或者调用静态对象的时候怎么将静态类设置成mock对象传入when()?
常见问题和解决方案简介
问题解决方案when(非mock.method)
在被测试类中,创建一个辅助类来处理静态方法调用。
在测试类中,调用辅助类的接口。
对象nullwhen.thenReturn 或者 doReturn.when 预置方法体执行需要的mock对象值。
SubscriptionManager
问题1:对象null
Cannot invoke "android.telephony.SubscriptionManager.getActiveSubscriptionInfoList()" because "this.mSubscriptionManager" is null
java.lang.NullPointerException: Cannot invoke "android.telephony.SubscriptionManager.getActiveSubscriptionInfoList()" because "this.mSubscriptionManager" is null
at com.demo.settings.util.SimHotSwapHandler.<init>(SimHotSwapHandler.java:32)
错误初始化方法,因为when不能传入非mock对象,是因为context没有mock初始化
@Before
public void setUp() {
// 将mock的SubscriptionManager与测试环境中Context的系统服务绑定
when(mockContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)).thenReturn(mockSubscriptionManager);
}
正常setup的方法:
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowSubscriptionManager;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = {33})
public class Test {
@Mock
private Context mockContext;
@Mock
private SubscriptionManager mockSubscriptionManager;
@Mock
private SubscriptionInfo mockSubscriptionInfo1;
@Mock
private SubscriptionInfo mockSubscriptionInfo2;
@Before
public void setUp() {
MockitoAnnotations.openMocks(this);
// 初始化使用Mock的Context
mockContext = mock(Context.class);
when(mockContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)).thenReturn(mockSubscriptionManager);
}
}
问题2:静态对象非mock,
//test报错代码
@Test
public void testGetUriForCurrSubId_validSubId() {
Uri baseUri = Uri.parse("content://test");
when(mockSubscriptionInfo.getSubscriptionId()).thenReturn(1);
//TODO: when 需要传入mock 对象
when(SubscriptionManager.isValidSubscriptionId(1)).thenReturn(true);
Uri resultUri = mFragment.getUriForCurrSubId(baseUri);
assertEquals(Uri.parse("content://test/subId/1"), resultUri);
}
报错console:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);Also, this error might show up because:
you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.inside when() you don't call method on mock but on some other object.
at com.demo.settings.DemoSettingsTest.testGetUriForCurrSubId_invalidSubId(DemoSettingsTest.java:305)
at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base@17.0.7/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base@17.0.7/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
分析:
在上述代码中,导致when()方法抛出错误的原因可能是尝试模拟静态方法。静态方法不能被直接模拟。
方案1、使用PowerMockito来模拟静态方法
通过使用PowerMockito,它提供了额外的功能来模拟静态方法。首先,包括适当的依赖项:在build.gradle文件中添加以下依赖项:
dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:4.2.0'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.9'
testImplementation 'org.powermock:powermock-module-junit4:2.0.9'
}
调整后的测试类:
@Test
public void testGetUriForCurrSubId_validSubId() {
Uri baseUri = Uri.parse("content://test");
when(mSubscriptionInfo.getSubscriptionId()).thenReturn(1);
//调整方案使用PowerMockit,直接用mockStatic会说对象从来没使用
PowerMockito.mockStatic(SubscriptionManager.class);
PowerMockito.when(SubscriptionManager.isValidSubscriptionId(1)).thenReturn(true);
Uri resultUri = uriGenerator.getUriForCurrSubId(baseUri
版权归原作者 Dic- 所有, 如有侵权,请联系我们删除。