42

Android Marshmallow引入的新權限方案需要在運行時檢查特定權限,這意味着需要根據用戶是拒絕還是允許訪問來提供不同的流程。Android Marshmallow:用Espresso測試權限?

由於我們使用Espresso在我們的應用上運行自動UI測試,我們如何模擬或更新權限狀態以測試不同的場景?

+0

可能重複[如何管理運行時權限android marshmallow espresso測試](http://stackoverflow.com/questions/32787234/how-to-manage-runtime-permissions-android-marshmallow-espresso-tests) – Caipivara

+0

嘗試這可能會對你有所幫助:-http://stackoverflow.com/a/41221852/5488468 –

回答

28

給人以這樣的靜態方法一試,當您的手機是英語語言環境:

private static void allowPermissionsIfNeeded() { 
    if (Build.VERSION.SDK_INT >= 23) { 
     UiDevice device = UiDevice.getInstance(getInstrumentation()); 
     UiObject allowPermissions = device.findObject(new UiSelector().text("Allow")); 
     if (allowPermissions.exists()) { 
      try { 
       allowPermissions.click(); 
      } catch (UiObjectNotFoundException e) { 
       Timber.e(e, "There is no permissions dialog to interact with "); 
      } 
     } 
    } 
} 

我發現它here

+3

請注意,這不適用於非EN語言環境或未來按鈕文本更改。如果製造商定製對話框,它甚至可能會因某些設備而失敗。 –

+4

奇怪的是,這不適用於LG Nexus 5與Android 6.沒有找到文本「允許」。使用以下工作:新的UiSelector()。clickable(true).checkable(false).index(1) – David

+1

你如何做到這一點咖啡測試? – Bhargav

9

其實有這樣做的2種方式,我知道迄今:

  1. 格蘭特之前開始測試使用ADB命令(documentation)權限:

adb shell pm grant "com.your.package" android.permission.your_permission

  • 您可以單擊權限對話框並使用UIAutomator設置權限(documentation)。如果您的測試是用Espresso for Android編寫的,您可以輕鬆將Espresso和UIAutomator步驟合併到一個測試中。
  • +0

    我不明白我們如何使用'adb shell'命令以及我們的測試套件。關於點擊對話框,Espresso應該能夠處理它自己。問題是,在運行測試並啓用權限後,下次運行測試時,它將失敗,因爲該設置會持續存在,並且對話框將不會再顯示。 – Soflete

    +1

    Espresso無法處理與權限對話框的交互,因爲dialog是其他應用程序的實例 - com.android.packageinstaller。 – denys

    +0

    您是否嘗試過使用UIAutomator接受彈出窗口?對我來說,它似乎沒有找到「允許」按鈕。任何想法如何解決這個問題? – conca

    31

    基於@riwnodennyk的解決方案,我們實現一個更好的。該接受的答案有兩個問題:

    • 如果設備是不是英文的,它不會工作
    • 如果您已經允許的權限之前,但您的應用程序已與文本的按鈕「允許」,它將在每次測試中被點擊,如果是權限對話框則無關緊要。

    所以,這裏的最終解決方案:

    public static void allowPermissionsIfNeeded(String permissionNeeded) { 
        try { 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasNeededPermission(permissionNeeded)) { 
         sleep(PERMISSIONS_DIALOG_DELAY); 
         UiDevice device = UiDevice.getInstance(getInstrumentation()); 
         UiObject allowPermissions = device.findObject(new UiSelector() 
          .clickable(true) 
          .checkable(false) 
          .index(GRANT_BUTTON_INDEX)); 
         if (allowPermissions.exists()) { 
          allowPermissions.click(); 
         } 
         } 
        } catch (UiObjectNotFoundException e) { 
         System.out.println("There is no permissions dialog to interact with"); 
        } 
        } 
    

    發現全班同學在這裏:https://gist.github.com/rocboronat/65b1187a9fca9eabfebb5121d818a3c4

    順便說一句,因爲這個答案一直是流行的,我們增加了PermissionGranter百瑞斯塔,我們上面的咖啡和UiAutomator工具,使儀器的測試綠色:https://github.com/SchibstedSpain/Barista檢查出來,COS,我們將保持它通過釋放釋放。

    +1

    創作奇蹟!也用於測試不同的語言環境,這是我的情況。 – Sloy

    +1

    太棒了!在大多數的答案中,人們不會採取護理設備的語言。所以,做得很好,謝謝! – alxsimo

    +0

    如果您還想測試拒絕權限,則可以複製該代碼,但將索引更改爲0。索引2是複選框,永遠不會再問我。 – Ethan

    19

    試驗是用類似運行之前,您可以授予權限:

    @Before 
    public void grantPhonePermission() { 
        // In M+, trying to call a number will trigger a runtime dialog. Make sure 
        // the permission is granted before running this test. 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
         getInstrumentation().getUiAutomation().executeShellCommand(
           "pm grant " + getTargetContext().getPackageName() 
             + " android.permission.CALL_PHONE"); 
        } 
    } 
    

    但你不能撤銷。如果您嘗試pm reset-permissionspm revoke...該進程被終止。

    +2

    我在google測試示例代碼中發現了類似的代碼。它適用於該軟件包中的電話手機示例應用程序,但如果在應用程序啓動後立即詢問權限(例如相機權限),則該功能無效。任何人有任何想法爲什麼? –

    +0

    你可以試試@BeforeClass。 –

    +0

    @ fangmobile.com也許是因爲該活動也是在@ Before規則中開始的? – nickmartens1980

    7

    您可以通過在開始測試之前授予權限輕鬆實現這一點。例如,如果你都應該在試運行過程中使用的攝像頭,您可以授權如下

    @Before 
    public void grantPermission() { 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
         getInstrumentation().getUiAutomation().executeShellCommand(
           "pm grant " + getTargetContext().getPackageName() 
             + " android.permission.CAMERA"); 
        } 
    } 
    
    +0

    ,您應該可以使用相同的方法撤銷權限,這對我很有用!我必須查看清單以準確找出使用此技術授予的權限。 – jerimiah797

    31

    隨着Android Testing Support Library 1.0的新版本,有一個GrantPermissionRule,你可以在你的測試使用前授予許可開始任何測試。

    @Rule public GrantPermissionRule permissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION); 
    
    +0

    它在你的測試中起作用嗎? –

    +0

    是的,沒有任何問題。 – Niklas

    +0

    工程就像一個魅力!查看[此博客文章](http://kotlindevelopment.com/runtime-permissions-espresso-done-right/)瞭解更多信息。 –

    0

    我知道答案已經但是接受,而不是已經暗示了一遍又一遍,另一種更好的方法是做在實際測試中,你要對特定下面的if聲明, OS版本:

    @Test 
    fun yourTestFunction() { 
        Assume.assumeTrue(Build.VERSION.SDK_INT >= 23) 
        // the remaining assertions... 
    } 
    

    如果assumeTrue函數調用評估,以虛假的表情,測試將停止和被忽略,這我假設是你想要什麼,此案正在設備上執行的測試pre SDK 23.

    1

    ESPRESSO UPDATE

    這種單一的代碼行授予列爲立即生效授權方法參數 每權限。換句話說,應用程序 會像對待,如果權限已經授予 - 沒有更多 對話框

    @Rule @JvmField 
    val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION) 
    

    和gradle這個

    dependencies { 
        ... 
        testImplementation "junit:junit:4.12" 
        androidTestImplementation "com.android.support.test:runner:1.0.0" 
        androidTestImplementation "com.android.support.test.espresso:espresso-core:3.0.0" 
        ... 
    } 
    

    參考:https://www.kotlindevelopment.com/runtime-permissions-espresso-done-right/

    0

    我已經實施了一個利用包裝類的解決方案,覆蓋並構建變體配置。解決方案需要很長時間才能解釋,可以在這裏找到:https://github.com/ahasbini/AndroidTestMockPermissionUtils

    現在還裝在一個SDK,但主要的想法是重寫的ContextWrapper.checkSelfPermissionActivityCompat.requestPermissions的功能來進行操作和返回嘲笑結果欺騙應用到不同的場景,就像進行測試:許可的情況下,因此拒絕該應用程序請求並在授予許可的情況下結束。即使應用程序一直都有權限,但這種情況也會發生,但它的想法是被重寫實現的模擬結果所欺騙。

    此外,該實現還有一個名爲PermissionRuleTestRule類,它可以在測試類中使用,以輕鬆模擬所有條件以無縫測試權限。例如,還可以確保應用程序稱爲requestPermissions()