הרחבת הבדיקות באמצעות מכשירים שמנוהלים על ידי גרסת ה-build

מכשירים שמנוהלים על ידי build משפרים את העקביות, הביצועים והמהימנות של הבדיקות המכשירות האוטומטיות שלכם. התכונה הזו, שזמינה ברמות API‏ 27 ומעלה, מאפשרת להגדיר מכשירי בדיקה וירטואליים או פיזיים מרחוק בקובצי Gradle של הפרויקט. התוסף Android Gradle משתמש בהגדרות כדי לנהל באופן מלא את המכשירים האלה – כלומר, ליצור, לפרוס ולבטל אותם – כשמריצים את הבדיקות האוטומטיות.

התכונה הזו מאפשרת לתוסף Android Gradle לראות לא רק את הבדיקות שאתם מריצים, אלא גם את מחזור החיים של המכשירים. כך משתפרת איכות חוויית הבדיקה בדרכים הבאות:

  • טיפול בבעיות שקשורות למכשיר כדי לוודא שהבדיקות יבוצעו
  • במכשירים וירטואליים, נעשה שימוש בתמונות מצב של האמולטור כדי לשפר את זמן ההפעלה של המכשיר ואת השימוש בזיכרון, וכדי לשחזר את המכשירים למצב נקי בין הבדיקות
  • התוצאות של הבדיקות נשמרות במטמון, ורק בדיקות שעשויות להניב תוצאות שונות מורצות מחדש
  • מספקת סביבה עקבית להרצת הבדיקות בין הרצות בדיקה מקומיות לבין הרצות בדיקה מרחוק

יצירת מכשיר וירטואלי שמנוהל על ידי Build

אתם יכולים לציין מכשיר וירטואלי שבו אתם רוצים להשתמש כדי לבדוק את האפליקציה בקובץ ה-build ברמת המודול. בדוגמה הבאה של קוד נוצר מכשיר Pixel 2 עם רמת API‏ 30 כמכשיר שמנוהל על ידי גרסת build.

Kotlin

android {
  testOptions {
    managedDevices {
      localDevices {
        create("pixel2api30") {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // Use only API levels 27 and higher.
          apiLevel = 30
          // To include Google services, use "google".
          systemImageSource = "aosp"
        }
      }
    }
  }
}

Groovy

android {
  testOptions {
    managedDevices {
      localDevices {
        pixel2api30 {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // Use only API levels 27 and higher.
          apiLevel = 30
          // To include Google services, use "google".
          systemImageSource = "aosp"
        }
      }
    }
  }
}

הגדרת קבוצות של מכשירים

כדי לעזור לכם להרחיב את הבדיקות לכמה הגדרות מכשיר, כמו רמות API שונות וגורמי צורה שונים, אתם יכולים להגדיר כמה מכשירים מנוהלי-build ולהוסיף אותם לקבוצה עם שם. לאחר מכן, הפלאגין Android Gradle יכול להריץ את הבדיקות במקביל בכל המכשירים בקבוצה.

בדוגמה הבאה אפשר לראות שני מכשירים שנוספו לקבוצת מכשירים בשם phoneAndTablet.

Kotlin

testOptions {
  managedDevices {
    localDevices {
      create("pixel2api29") { ... }
      create("nexus9api30") { ... }
    }
    groups {
      create("phoneAndTablet") {
        targetDevices.add(devices["pixel2api29"])
        targetDevices.add(devices["nexus9api30"])
      }
    }
  }
}

Groovy

testOptions {
  managedDevices {
    localDevices {
      pixel2api29 { ... }
      nexus9api30 { ... }
    }
    groups {
      phoneAndTablet {
        targetDevices.add(devices.pixel2api29)
        targetDevices.add(devices.nexus9api30)
      }
    }
  }
}

הרצת הבדיקות

כדי להריץ את הבדיקות באמצעות המכשירים המנוהלים על ידי ה-build שהגדרתם, משתמשים בפקודה הבאה. ‫device-name הוא שם המכשיר שהגדרתם בסקריפט ה-build של Gradle (למשל pixel2api30), ו-BuildVariant הוא וריאציית ה-build של האפליקציה שרוצים לבדוק, למשל Debug.

‫Linux ו-macOS

./gradlew device-nameBuildVariantAndroidTest

Windows

gradlew device-nameBuildVariantAndroidTest

כדי להריץ את הבדיקות בקבוצה של מכשירים בניהול Gradle, משתמשים בפקודה הבאה.

‫Linux ו-macOS

./gradlew group-nameGroupBuildVariantAndroidTest
./gradlew group-nameGroupBuildVariantAndroidTest

Windows

gradlew group-nameGroupBuildVariantAndroidTest

פלט הבדיקה כולל נתיב לקובץ HTML עם דוח הבדיקה. אפשר גם לייבא את תוצאות הבדיקה ל-Android Studio כדי לבצע ניתוח נוסף. לשם כך, לוחצים על Run > Test History (הפעלה > היסטוריית בדיקות) בסביבת הפיתוח המשולבת (IDE).

הפעלת חלוקת בדיקות

מכשירים שמנוהלים על ידי Build תומכים בפיצול בדיקות (test sharding), שמאפשר לפצל את חבילת הבדיקות למספר מופעים זהים של מכשירים וירטואליים, שנקראים shards, שפועלים במקביל. שימוש בפיצול בדיקות יכול לעזור לקצר את הזמן הכולל של ביצוע הבדיקות, אבל הוא דורש משאבי מחשוב נוספים.

כדי להגדיר את מספר הרסיסים שרוצים להשתמש בהם בהרצת בדיקה מסוימת, מגדירים את הערך הבא בקובץ gradle.properties:

android.experimental.androidTest.numManagedDeviceShards=<number_of_shards>

כשמריצים בדיקות באמצעות האפשרות הזו, מכשירים שמנוהלים על ידי build מקצים את מספר הרסיסים שצוין לכל פרופיל מכשיר בהרצת הבדיקה. לדוגמה, אם פרסתם את הבדיקות לקבוצת מכשירים של שלושה מכשירים והגדרתם את numManagedDeviceShards ל-2, מכשירים בניהול build יקצו סך של שישה מכשירים וירטואליים להרצת הבדיקה.

כשהבדיקות מסתיימות, Gradle מוציא פלט של תוצאות הבדיקה בקובץ .proto לכל שבר שנעשה בו שימוש בהרצת הבדיקה.

שימוש במכשירי בדיקה אוטומטיים

מכשירים שמנוהלים על ידי build תומכים בסוג של מכשיר אמולטור שנקרא Automated Test Device (ATD, מכשיר בדיקה אוטומטי), שעבר אופטימיזציה כדי להפחית את השימוש במשאבי CPU וזיכרון כשמריצים את הבדיקות המכשירות. השימוש ב-ATD משפר את ביצועי זמן הריצה בכמה דרכים:

  • הסרת אפליקציות שמותקנות מראש ובדרך כלל לא שימושיות לבדיקת האפליקציה
  • השבתה של שירותי רקע מסוימים שבדרך כלל לא שימושיים לבדיקת האפליקציה
  • השבתה של עיבוד באמצעות חומרה

לפני שמתחילים, חשוב לעדכן את Android Emulator לגרסה העדכנית ביותר שזמינה. לאחר מכן, מציינים תמונה עם ‎-atd כשמגדירים מכשיר שמנוהל על ידי build בקובץ ה-build ברמת המודול, כמו בדוגמה הבאה:

Kotlin

android {
  testOptions {
    managedDevices {
      localDevices {
        create("pixel2api30") {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // ATDs currently support only API level 30.
          apiLevel = 30
          // You can also specify "google-atd" if you require Google Play Services.
          systemImageSource = "aosp-atd"
        }
      }
    }
  }
}

Groovy

android {
  testOptions {
    managedDevices {
      localDevices {
        pixel2api30 {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // ATDs currently support only API level 30.
          apiLevel = 30
          // You can also specify "google-atd" if you require Google Play Services.
          systemImageSource = "aosp-atd"
        }
      }
    }
  }
}

אפשר גם ליצור קבוצות מכשירים, כמו במכשירים אחרים שמנוהלים על ידי Build. כדי ליהנות עוד יותר מהשיפורים בביצועים, אפשר גם להשתמש ב-ATD עם חלוקת בדיקות כדי לקצר את הזמן הכולל של הרצת הבדיקות בחבילת הבדיקות.

מה מוסר מתמונות ATD?

בנוסף להפעלה במצב headless, מכשירי ATD גם מבצעים אופטימיזציה של הביצועים על ידי הסרה או השבתה של אפליקציות ושירותים שבדרך כלל לא נדרשים לבדיקת הקוד של האפליקציה. בטבלה שלמטה מופיע סקירה כללית של הרכיבים שהסרנו או השבתנו בתמונות ובתיאורים של ATD, והסבר למה הם לא שימושיים.

מה מוסר מתמונות ATD למה יכול להיות שלא תצטרכו את זה כשמריצים בדיקות אוטומטיות
אפליקציות של מוצרי Google:
  • אימייל
  • מפות
  • Chrome
  • Messages
  • חנות Play ואחרים
הבדיקות האוטומטיות צריכות להתמקד בלוגיקה של האפליקציה שלכם, תוך הנחה שאפליקציות אחרות או הפלטפורמה יפעלו בצורה תקינה.

בעזרת Espresso-Intents, אתם יכולים להתאים ולאמת את הכוונות היוצאות שלכם, או אפילו לספק תשובות stub במקום תשובות כוונה בפועל.

אפליקציות ושירותים של הגדרות:
  • CarrierConfig
  • EmergencyInfo
  • OneTimeInitializer
  • PhotoTable (שומרי מסך)
  • הקצאה
  • אפליקציית ההגדרות
  • StorageManager
  • הגדרת APN לטלפוניה
  • WallpaperCropper
  • WallpaperPicker
האפליקציות האלה מציגות ממשק משתמש גרפי למשתמשי הקצה, שמאפשר להם לשנות את הגדרות הפלטפורמה, להגדיר את המכשיר או לנהל את נפח האחסון במכשיר. בדרך כלל, הבדיקות האלה לא נכללות בבדיקות אוטומטיות ברמת האפליקציה.


הערה: ספק ההגדרות עדיין זמין בתמונה של ATD.

SystemUI הבדיקות האוטומטיות צריכות להתמקד בלוגיקה של האפליקציה שלכם, תוך הנחה שאפליקציות אחרות או הפלטפורמה יפעלו בצורה תקינה.
אפליקציות ושירותים של AOSP:
  • דפדפן 2
  • יומן
  • Camera2
  • אנשי הקשר
  • Dialer
  • DeskClock
  • Gallery2
  • ‫LatinIME
  • Launcher3QuickStep
  • מוזיקה
  • QuickSearchBox
  • SettingsIntelligence
האפליקציות והשירותים האלה בדרך כלל לא נכללים בהיקף הבדיקות האוטומטיות של הקוד של האפליקציה.

שימוש במכשירים של Firebase Test Lab

כשמשתמשים במכשירים בניהול build, אפשר להריץ את הבדיקות האוטומטיות עם מכשור בקנה מידה גדול במכשירים של Firebase Test Lab. ב-Test Lab אפשר להריץ את הבדיקות בו-זמנית במגוון רחב של מכשירי Android, פיזיים וגם וירטואליים. הבדיקות האלה מופעלות במרכזי נתונים מרוחקים של Google. בעזרת תמיכה במכשירים מנוהלי-build, מערכת ה-build יכולה לנהל באופן מלא את הרצת הבדיקות במכשירים האלה של Test Lab על סמך ההגדרות שלכם.

שנתחיל?

בשלבים הבאים מוסבר איך להתחיל להשתמש במכשירים של Firebase Test Lab עם מכשירים שמנוהלים על ידי build. בשלבים האלה משתמשים ב-CLI של gcloud כדי לספק פרטי כניסה של משתמש, וזה לא תמיד מתאים לכל סביבות הפיתוח. למידע נוסף על תהליך האימות שמתאים לצרכים שלכם, תוכלו לקרוא את המאמר הסבר על Application Default Credentials.

  1. כדי ליצור פרויקט Firebase, עוברים אל מסוף Firebase. לוחצים על הוספת פרויקט ופועלים לפי ההנחיות במסך כדי ליצור פרויקט. חשוב לזכור את מזהה הפרויקט.

  2. כדי להתקין את Google Cloud CLI, פועלים לפי השלבים במאמר התקנת gcloud CLI.

  3. מגדירים את הסביבה המקומית.

    1. מקשרים לפרויקט Firebase ב-gcloud:

      gcloud config set project FIREBASE_PROJECT_ID
      
    2. מאשרים את השימוש בפרטי הכניסה של המשתמש לצורך גישה ל-API. מומלץ להעביר קובץ JSON של חשבון שירות ל-Gradle באמצעות DSL בסקריפט ה-build ברמת המודול כדי לאשר גישה:

      Kotlin

      firebaseTestLab {
        ...
        serviceAccountCredentials.set(file(SERVICE_ACCOUNT_JSON_FILE))
      }

      Groovy

      firebaseTestLab {
        ...
        serviceAccountCredentials = file(SERVICE_ACCOUNT_JSON_FILE)
      }

      אפשר גם להשתמש בפקודה הבאה במסוף כדי לבצע הרשאה באופן ידני:

      gcloud auth application-default login
      
    3. אופציונלי: מוסיפים את פרויקט Firebase כפרויקט המכסה. השלב הזה נדרש רק אם חרגתם מהמכסה ללא עלות של Test Lab.

      gcloud auth application-default set-quota-project FIREBASE_PROJECT_ID
      
  4. מפעילים את ממשקי ה-API הנדרשים.

    בדף API Library ב-Google Developers Console, מזינים את שמות ה-API הבאים בתיבת החיפוש בחלק העליון של המסוף, ואז לוחצים על Enable API בדף הסקירה הכללית של כל API כדי להפעיל את Cloud Testing API ואת Cloud Tool Results API.

  5. מגדירים את פרויקט Android.

    1. מוסיפים את הפלאגין Firebase Test Lab בסקריפט הבנייה ברמה העליונה:

      Kotlin

      plugins {
        ...
        id("com.google.firebase.testlab") version "0.0.1-alpha05" apply false
      }

      Groovy

      plugins {
        ...
        id 'com.google.firebase.testlab' version '0.0.1-alpha05' apply false
      }
    2. הפעלת סוגי מכשירים מותאמים אישית בקובץ gradle.properties:

      android.experimental.testOptions.managedDevices.customDevice=true
    3. מוסיפים את הפלאגין Firebase Test Lab לסקריפט ה-build ברמת המודול:

      Kotlin

      plugins {
       ...
       id "com.google.firebase.testlab"
      }

      Groovy

      plugins {
       ...
       id 'com.google.firebase.testlab'
      }

ציון מכשיר ב-Test Lab

אתם יכולים לציין מכשיר Firebase Test Lab ש-Gradle ישתמש בו לבדיקת האפליקציה בסקריפט build ברמת המודול. בדוגמה הבאה של קוד נוצר מכשיר Pixel 3 עם API ברמה 30 כמכשיר Test Lab שמנוהל על ידי build ונקרא ftlDevice. הבלוק firebaseTestLab {} זמין כשמחילים את הפלאגין com.google.firebase.testlab על המודול.

Kotlin

firebaseTestLab {
  managedDevices {
    create("ftlDevice") {
      device = "Pixel3"
      apiLevel = 30
    }
  }
  ...
}

Groovy

firebaseTestLab {
  managedDevices {
    ftlDevice {
      device = "Pixel3"
      apiLevel = 30
    }
  }
  ...
}

כדי להגדיר קבוצה של מכשירים שמנוהלים על ידי Build, כולל מכשירים של Firebase Test Lab, אפשר לעיין במאמר בנושא הגדרת קבוצות של מכשירים.

כדי להריץ את הבדיקות, משתמשים באותן פקודות שמשמשות להרצת מכשירים אחרים שמנוהלים על ידי build. שימו לב: Gradle לא מריץ בדיקות במקביל ולא תומך בהגדרות אחרות של Google Cloud CLI למכשירים ב-Test Lab.

אופטימיזציה של הרצת בדיקות באמצעות חלוקה חכמה

בדיקה במכשירי Test Lab שמנוהלים על ידי build תומכת בפיצול חכם. החלוקה החכמה (Smart sharding) מחלקת אוטומטית את הבדיקות בין חלקי ה-shard כך שכל חלק יפעל בערך אותו פרק זמן. כך מצטמצם הצורך בהקצאה ידנית ומתקצר משך הפעלת הבדיקה הכולל. התכונה 'חלוקה חכמה' משתמשת בהיסטוריית הבדיקות שלכם או במידע על משך הזמן שלקח להריץ את הבדיקות בעבר, כדי לחלק את הבדיקות בצורה אופטימלית. שימו לב שצריך להשתמש בגרסה 0.0.1-alpha05 של הפלאגין Gradle בשביל Firebase Test Lab כדי להשתמש בפיצול חכם.

כדי להפעיל חלוקה חכמה, מציינים את משך הזמן שצריכות להימשך הבדיקות בכל שבר. כדי למנוע מצב שבו רסיסים מבוטלים לפני שהבדיקות מסתיימות, כדאי להגדיר את משך הזמן של רסיס היעד לפחות חמש דקות פחות מ-timeoutMinutes.

firebaseTestLab {
  ...
  testOptions {
    targetedShardDurationMinutes = 2
  }
}

מידע נוסף זמין במאמר בנושא אפשרויות DSL של מכשירים ב-Firebase Test Lab.

עדכון של DSL למכשירים ב-Test Lab

יש עוד אפשרויות של DSL שאפשר להגדיר כדי להתאים אישית את הרצת הבדיקות או לבצע מיגרציה מפתרונות אחרים שכבר נמצאים בשימוש. אפשר לראות חלק מהאפשרויות האלה בקטע הקוד הבא.

firebaseTestLab {
  ...

  /**
   * A path to a JSON file that contains service account credentials to access to
   * a Firebase Test Lab project.
   */
  serviceAccountCredentials.set(file("your_service_account_credentials.json"))


  testOptions {
    fixture {
      /**
       * Whether to grant permissions on the device before tests begin.
       * Available options are "all" or "none".
       *
       * Default value is "all".
       */
      grantedPermissions = "all"

      /**
       * Map of files to push to the device before starting the test.
       *
       * The key is the location on the device.
       * The value is the location of the file, either local or in Google Cloud.
       */
      extraDeviceFiles["/sdcard/dir1/file1.txt"] = "local/file.txt"
      extraDeviceFiles["/sdcard/dir2/file2.txt"] = "gs://bucket/file.jpg"

      /**
       * The name of the network traffic profile.
       *
       * Specifies network conditions to emulate when running tests.
       *
       * Default value is empty.
       */
      networkProfile = "LTE"
    }

    execution {
      /**
       * The maximum time to run the test execution before cancellation,
       * measured in minutes. Does not include the setup or teardown of device,
       * and is handled server-side.
       *
       * The maximum possible testing time is 45 minutes on physical devices
       * and 60 minutes on virtual devices.
       *
       * Defaults to 15 minutes.
       */
       timeoutMinutes = 30

      /**
       * Number of times the test should be rerun if tests fail.
       * The number of times a test execution should be retried if one
       * or more of its test cases fail.
       *
       * The max number of times is 10.
       *
       * The default number of times is 0.
       */
      maxTestReruns = 2

      /**
       * Ensures only a single attempt is made for each execution if
       * an infrastructure issue occurs. This doesn't affect `maxTestReruns`.
       * Normally, two or more attempts are made by Firebase Test Lab if a
       * potential infrastructure issue is detected. This is best enabled for
       * latency sensitive workloads. The number of execution failures might be
       * significantly greater with `failFast` enabled.
       *
       * Defaults to false.
       */
      failFast = false

      /**
       * The number of shards to split the tests across.
       *
       * Default to 0 for no sharding.
       */
      numUniformShards = 20
    }

    /**
     * For smart sharding, the target length of time each shard should takes in
     * minutes. Maxes out at 50 shards for physical devices and 100 shards for
     * virtual devices.
     *
     * Only one of numUniformShards or targetedShardDurationMinutes can be set.
     *
     * Defaults to 0 for no smart sharding.
     */
     targetedShardDurationMinutes = 15
    }

    results {
      /**
       * The name of the Google storage bucket to store the test results in.
       *
       * If left unspecified, the default bucket is used.
       *
       * Please refer to Firebase Test Lab permissions for required permissions
       * for using the bucket.
       */
      cloudStorageBucket = "bucketLocationName"

      /**
       * Name of test results for the Firebase console history list.
       * All tests results with the same history name are grouped
       * together in the Firebase console in a time-ordered test history list.
       *
       * Defaults to the application label in the APK manifest.
       */
      resultsHistoryName = "application-history"

      /**
       * List of paths to copy from the test device's storage to the test
       * results folder. These must be absolute paths under /sdcard or
       * /data/local/tmp.
       */
      directoriesToPull.addAll(
        "/sdcard/path/to/something"
      )

      /**
       * Whether to enable video recording during the test.
       *
       * Disabled by default.
       */
      recordVideo = false

      /**
       * Whether to enable performance metrics. If enabled, monitors and records
       * performance metrics such as CPU, memory, and network usage.
       *
       * Defaults to false.
       */
      performanceMetrics = true
  }
}