如何使用Mock修改Android设备上的features
手工测试过程中有个测试场景需要删除测试设备上某个Android feature,往上搜索了一圈没找到有效的操作方法。获取Android设备所有的feature可以通过adb命令pm list features或者Android代码Context.getPackageManager().getSystemAvailableFeatures(),但都没有对应的修改方法。
既然feature是从Context获取的,那能不能构造一个只包含我想要的feature的Context呢。顺着这个思路,有了下面的方案。
方案设计单元测试常用的Mock技术,就是来构造假/模拟对象的。但如果完全构造,又担心和真实环境差别较大,测试结果不可靠。能不能从真实Android设备中获取真实的Context,把不想要的feature去除,再给到被测试方法中呢?
答案是肯定的,通过选用流行的Mock组件Mockito ,官网上给出了下面2种Mock Java对象的方式:
mock()/@Mock: create mock spy()/@Spy: partial mocking, real methods are invoked but still can be verified and stubbed可以看到Spy这种Mock方式可完美地解决我的需求。
实现(简化版需求)业务需求说明获取所有Android Features并把feature name打印在日志中,使用adb命令的效果如下:
➜ study git:(master) ✗ adb shell pm list features feature:reqGlEsVersion=0x30002feature:android.hardware.audio.outputfeature:android.hardware.bluetoothfeature:android.hardware.bluetooth_lefeature:android.hardware.camerafeature:android.hardware.camera.anyfeature:android.hardware.camera.autofocusfeature:android.hardware.camera.capability.manual_post_processingfeature:android.hardware.camera.capability.manual_sensorfeature:android.hardware.camera.capability.rawfeature:android.hardware.camera.flashfeature:android.hardware.camera.frontfeature:android.hardware.camera.level.fullfeature:android.hardware.faketouchfeature:android.hardware.locationfeature:android.hardware.location.gpsfeature:android.hardware.location.networkfeature:android.hardware.microphonefeature:android.hardware.nfc.anyfeature:android.hardware.opengles.aepfeature:android.hardware.ram.normalfeature:android.hardware.screen.landscapefeature:android.hardware.screen.portraitfeature:android.hardware.sensor.accelerometerfeature:android.hardware.sensor.compassfeature:android.hardware.sensor.lightfeature:android.hardware.sensor.proximityfeature:android.hardware.sensor.stepcounterfeature:android.hardware.telephonyfeature:android.hardware.telephony.cdmafeature:android.hardware.telephony.gsmfeature:android.hardware.touchscreenfeature:android.hardware.touchscreen.multitouchfeature:android.hardware.touchscreen.multitouch.distinctfeature:android.hardware.touchscreen.multitouch.jazzhandfeature:android.hardware.usb.accessoryfeature:android.hardware.usb.hostfeature:android.hardware.vulkan.computefeature:android.hardware.vulkan.levelfeature:android.hardware.vulkan.version=4194307feature:android.hardware.wififeature:android.hardware.wifi.directfeature:android.software.activities_on_secondary_displaysfeature:android.software.app_widgetsfeature:android.software.autofillfeature:android.software.backupfeature:android.software.companion_device_setupfeature:android.software.connectionservicefeature:android.software.ctsfeature:android.software.device_adminfeature:android.software.file_based_encryptionfeature:android.software.input_methodsfeature:android.software.live_wallpaperfeature:android.software.managed_usersfeature:android.software.midifeature:android.software.picture_in_picturefeature:android.software.printfeature:android.software.securely_removes_usersfeature:android.software.sipfeature:android.software.sip.voipfeature:android.software.verified_bootfeature:android.software.voice_recognizersfeature:android.software.webview业务需求代码实现
public class FeaturesUtil { private static final String TAG = 'FeaturesUtil'; public static void getFeatures(Context context) {PackageManager packageManager = context.getPackageManager();FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures();for (FeatureInfo featureInfo : featureInfos) { Log.i(TAG, 'feature: ' + featureInfo.name);} }}测试代码实现(去除bluetooth feature)
@Spy Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();; @Spy PackageManager packageManager = context.getPackageManager();@Test public void getFeatures() {// 去除bluetooth featureFeatureInfo[] mockedFeatureInfos = removeFeature(packageManager.getSystemAvailableFeatures(),Arrays.asList('android.hardware.bluetooth', 'android.hardware.bluetooth_le'));when(packageManager.getSystemAvailableFeatures()).thenReturn(mockedFeatureInfos);when(context.getPackageManager()).thenReturn(packageManager);FeaturesUtil.getFeatures(context); } /** * 根据feature name删除一个或多个feature * * @param featureInfos FeatureInfo数组 * @param featureNames 字符串列表,每个元素是要删除的FeatureInfo的name * @return 删除之后的FeatureInfo数组 */ private FeatureInfo[] removeFeature(FeatureInfo[] featureInfos, List<String> featureNames) {List<FeatureInfo> featureInfoList = new ArrayList();for (FeatureInfo featureInfo : featureInfos) { if (featureInfo.name != null && !(featureNames.contains(featureInfo.name))) {featureInfoList.add(featureInfo); }}return featureInfoList.toArray(new FeatureInfo[featureInfoList.size()]); }运行测试代码后Logcat输出
可以看到bluetooth相关的feature已经没有了
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.sensor.proximity
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.sensor.accelerometer
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.faketouch
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.usb.accessory
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.telephony.cdma
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.backup
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.touchscreen
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.touchscreen.multitouch
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.print
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.activities_on_secondary_displays
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.voice_recognizers
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.picture_in_picture
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.opengles.aep
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera.autofocus
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.telephony.gsm
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.sip.voip
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.usb.host
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.audio.output
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.verified_boot
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera.flash
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera.front
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.screen.portrait
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.microphone
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.autofill
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.securely_removes_users
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.sensor.compass
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.hardware.touchscreen.multitouch.jazzhand
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.app_widgets
2021-04-07 13:23:39.266 16238-16268/? I/FeaturesUtil: feature: android.software.input_methods
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.sensor.light
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.vulkan.version
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.companion_device_setup
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.device_admin
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.screen.landscape
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.ram.normal
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.managed_users
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.webview
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.sensor.stepcounter
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera.capability.manual_post_processing
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera.any
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera.capability.raw
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.vulkan.compute
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.connectionservice
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.touchscreen.multitouch.distinct
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.location.network
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.cts
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.sip
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera.capability.manual_sensor
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.camera.level.full
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.wifi.direct
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.live_wallpaper
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.location.gps
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.software.midi
2021-04-07 13:23:39.267 16238-16268/? I/FeaturesUtil: feature: android.hardware.nfc.any
2021-04-07 13:23:39.268 16238-16268/? I/FeaturesUtil: feature: android.hardware.wifi
2021-04-07 13:23:39.268 16238-16268/? I/FeaturesUtil: feature: android.hardware.location
2021-04-07 13:23:39.268 16238-16268/? I/FeaturesUtil: feature: android.hardware.vulkan.level
2021-04-07 13:23:39.268 16238-16268/? I/FeaturesUtil: feature: android.hardware.telephony
2021-04-07 13:23:39.268 16238-16268/? I/FeaturesUtil: feature: android.software.file_based_encryption
2021-04-07 13:23:39.269 16238-16268/? I/TestRunner: finished: getFeatures(com.aniu.featuresmock.FeaturesUtilTest)
总结 不直接使用Mock,而是使用Spy,最大限度保持测试环境真实可靠,从而保证测试效果 测试代码不要放在test目录,要放在androidTest目录,保证在真实设备上跑(不然代码也会报错)。目录结构如下:以上就是如何使用Mock修改Android设备上的features的详细内容,更多关于Mock修改Android features的资料请关注好吧啦网其它相关文章!
相关文章: