如何编写模拟 GPS 位置的 Espresso 测试并在 Google Testlab 中使用它们?

Posted

技术标签:

【中文标题】如何编写模拟 GPS 位置的 Espresso 测试并在 Google Testlab 中使用它们?【英文标题】:How to write Espresso Tests which are mocking GPS locations and use them in Google Testlab? 【发布时间】:2019-02-25 15:47:27 【问题描述】:

我使用 Espresso Recorder 录制了浓缩咖啡测试。我想在我的应用中测试一些位置变化。

目前我正在使用以下代码模拟位置:

LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy( Criteria.ACCURACY_FINE );

String mocLocationProvider = LocationManager.GPS_PROVIDER;//lm.getBestProvider( criteria, true );

lm.addTestProvider(mocLocationProvider, false, false,
        false, false, true, true, true, 0, 5);
lm.setTestProviderEnabled(mocLocationProvider, true);

Location loc = new Location(mocLocationProvider);
Location mockLocation = new Location(mocLocationProvider); // a string
mockLocation.setLatitude(-26.902038);  // double
mockLocation.setLongitude(-48.671337);
mockLocation.setAltitude(loc.getAltitude());
mockLocation.setTime(System.currentTimeMillis());
mockLocation.setAccuracy(1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) 
    mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());

lm.setTestProviderLocation( mocLocationProvider, mockLocation);

我还在调试清单文件中添加了权限:

<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>

但不幸的是,我仍然遇到安全异常:

java.lang.SecurityException: mypackage.test from uid not allowed to perform MOCK_LOCATION

我想在 Google Firebase 测试实验室中使用模拟位置运行记录的测试用例。我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

基本上,您必须在 devs 选项中启用该应用程序(选择模拟位置应用程序)。由于您无法控制谷歌平台上的设备,因此您必须使用ADB命令来启用它。

appops set yourPackageName android:mock_location allow

例如,这就是我在 @before 函数中为我的模拟位置测试所做的:

@Before
fun grantPermission() 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
        with(getInstrumentation().uiAutomation) 
            ...
            executeShellCommand("appops set " + InstrumentationRegistry.getTargetContext().packageName + " android:mock_location allow")
            Thread.sleep(1000)
            ...
        
    

基于这种方法,请注意,如果您插入任何新设备,您还可以为您的 gradle 任务创建一个 sn-p,以便在您的工作站上自动执行此操作。例如:How to set Allow Mock Location on Android Device before executing AndroidTest with uiautomator and espresso?

希望有帮助!

【讨论】:

【参考方案2】:

MrAurelien 提出了一个很好的解决方案。但最好以不同的方式实现它。

Thread.sleep(1000) 使您的测试变慢且不稳定。这是一个运行稳定的不同版本。

@Before
fun grantPermission() 
    instrumentation.uiAutomation.executeShellCommandBlocking(
        "appops set $appContext.packageName android:mock_location allow"
    )

executeShellCommandBlocking 是一个自定义 utils 函数,它等待 appops 命令完成。

fun UiAutomation.executeShellCommandBlocking(command: String) 
    val output = executeShellCommand(command)
    FileInputStream(output.fileDescriptor).use  it.readBytes() 

我们在Mapbox Android Navigation SDK 中使用此解决方案。

【讨论】:

以上是关于如何编写模拟 GPS 位置的 Espresso 测试并在 Google Testlab 中使用它们?的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 中使用 GPS 获取当前位置

gps如何测量面积实例

怎么让手机模拟gps地图位置信息?

模拟 GPS 位置后是不是可以在模拟模式打开后获取原始位置?

gps位置模拟器在的使用价值

gps位置模拟器在的使用价值