בניית בדיקות יחידה מקומית

בדיקה מקומית פועלת ישירות בתחנות העבודה שלכם, ולא ב-Android המכשיר או אמולטור. לכן, הוא משתמש במכונה הווירטואלית Java (JVM) המקומית שלכם במקום מכשיר Android כדי להריץ בדיקות. בדיקות מקומיות מאפשרות לכם להעריך את התוצאות את הלוגיקה של האפליקציה במהירות רבה יותר. אבל לא תהיה לנו אפשרות לקיים אינטראקציה עם מסגרת Android יוצרת הגבלה על סוגי הבדיקות שאפשר להריץ.

בדיקה של יחידה מאמתת את ההתנהגות של קטע קטן של קוד, היחידה בדיקה. הוא עושה זאת על ידי הרצת הקוד ובדיקת התוצאה.

בדיקות יחידה הן בדרך כלל פשוטות, אבל ההגדרה שלהן עלולה להיות בעייתית, כאשר 'בבדיקה' לא נועדה להביא בחשבון את יכולת הבדיקה:

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

למידע על אסטרטגיות נפוצות לבדיקת יחידות ב-Android, קראו את המאמר מה צריך? בדיקה.

מיקום בדיקות מקומיות

כברירת מחדל, קובצי המקור עבור בדיקות של יחידה מקומית נמצאים module-name/src/test/ הספרייה הזו כבר קיימת כשיוצרים תיקייה חדשה בפרויקט באמצעות Android Studio.

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

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

כדי לעשות זאת, צריך לפתוח את הקובץ build.gradle של המודול של האפליקציה ולציין את הפרטים הבאים של ספריות כיחסי תלות. צריך להשתמש בפונקציה testImplementation כדי לציין שהם חלים על קבוצת מקור הבדיקה המקומית, ולא על האפליקציה:

dependencies {
  // Required -- JUnit 4 framework
  testImplementation "junit:junit:$jUnitVersion"
  // Optional -- Robolectric environment
  testImplementation "androidx.test:core:$androidXTestVersion"
  // Optional -- Mockito framework
  testImplementation "org.mockito:mockito-core:$mockitoVersion"
  // Optional -- mockito-kotlin
  testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
  // Optional -- Mockk framework
  testImplementation "io.mockk:mockk:$mockkVersion"
}

יצירת כיתה לבדיקת יחידה מקומית

אתם כותבים את הכיתה של בדיקת היחידה המקומית ככיתת מבחן של JUnit 4.

כדי לעשות זאת, צריך ליצור כיתה שמכילה שיטת בדיקה אחת או יותר, בדרך כלל module-name/src/test/ שיטת בדיקה מתחילה עם ההערה @Test ו- מכיל את הקוד להפעלה ואימות של היבט יחיד של הרכיב שאתם רוצים לבדוק.

הדוגמה הבאה ממחישה איך מטמיעים מחלקה של בדיקת יחידה מקומית. שיטת בדיקה emailValidator_correctEmailSimple_returnsTrue()מנסה לבצע אימות isValidEmail(),שהיא שיטה באפליקציה. פונקציית הבדיקה תחזיר True אםisValidEmail() גם מחזירה True.

Kotlin

import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class EmailValidatorTest {
  @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"))
  }

}

Java

import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

class EmailValidatorTest {
  @Test
  public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"));
  }
}

עליך ליצור בדיקות קריאות שמעריכות אם הרכיבים האפליקציה תחזיר את התוצאות הצפויות. מומלץ להשתמש בספריית טענות נכונות (assertions), בתור junit.Assert, Hamcrest, או האמת. קטע הקוד שלמעלה הוא דוגמה לאופן השימוש junit.Assert

ספריית Android שאפשר ליצור בה הדמיה

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

כך אפשר לבנות בדיקות מקומיות כשמפנות למחלקות ב-Android. כמו Context. וחשוב יותר, היא מאפשרת להשתמש את ה-framework עם המחלקות של Android.

הדמיית יחסי תלות של Android

בעיה טיפוסית היא לגלות שכיתה משתמשת במשאב מחרוזות. אפשר לקבל משאבי מחרוזות באמצעות קריאה ל-method getString() ב-Context בכיתה. עם זאת, בדיקה מקומית לא יכולה להשתמש ב-Context או בכל אחת מהשיטות שלה כי שייכים ל-framework של Android. במצב אידיאלי, השיחה אל getString() תהיה עברו מהכיתה, אבל לא תמיד זה מעשי. הפתרון הוא יוצרים הדמיה או stub של Context שתמיד מחזירים את אותו ערך השיטה getString() הופעלה.

באמצעות ספריית Android שניתן ליצור בה הדמיה ומסגרות לעג, כמו אפשר לתכנת את Mockito או MockK התנהגות החיקויים של מחלקות Android בבדיקות היחידה.

כדי להוסיף אובייקט מדומה לבדיקת היחידה המקומית באמצעות Mockito, מבצעים את הפעולות הבאות מודל תכנות:

  1. כוללים את התלות של ספריית Mockito בקובץ build.gradle, באופן הבא: שמתואר בהגדרת סביבת הבדיקה.
  2. בתחילת ההגדרה של הכיתה בבדיקת היחידה, מוסיפים את הפקודה הערה אחת (@RunWith(MockitoJUnitRunner.class)). הערה זו מראה מריץ בדיקה לדוגמה כדי לוודא שהשימוש שלך ב-framework נכון מפשט את האתחול של אובייקטים לדוגמה.
  3. כדי ליצור אובייקט מדומה על תלות ב-Android, יש להוסיף את ההערה @Mock לפני הצהרת השדה.
  4. כדי לפגוע בהתנהגות של התלות, אפשר לציין תנאי של הערך המוחזר כשהתנאי מתקיים באמצעות הפונקציה when() ו-thenReturn() שיטות.

הדוגמה הבאה ממחישה איך אפשר ליצור בדיקת יחידה שמבוססת על מודל אובייקט Context ב-Kotlin שנוצר באמצעות Mockito-Kotlin.

import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {

  @Mock
  private lateinit var mockContext: Context

  @Test
  fun readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    val mockContext = mock<Context> {
        on { getString(R.string.name_label) } doReturn FAKE_STRING
    }

    val myObjectUnderTest = ClassUnderTest(mockContext)

    // ...when the string is returned from the object under test...
    val result: String = myObjectUnderTest.getName()

    // ...then the result should be the expected one.
    assertEquals(result, FAKE_STRING)
  }
}

מידע נוסף על השימוש ב-Mockito framework זמין ב-Mockito API והכיתה SharedPreferencesHelperTest ב קוד לדוגמה. כדאי לנסות גם את Android Testing Codelab.

שגיאה: "השיטה ... לא mocked"

אם מנסים לגשת לאחד מהדפדפנים, ספריית Android ניתנת להדמיה גורמת לחריגה מברירת המחדל. שיטות עם ההודעה Error: "Method ... not mocked.

אם החריגות שמזוהות בעייתיות בבדיקות שלך, אפשר לשנות את כך ש-methods יחזירו null או אפס, בהתאם . כדי לעשות זאת, צריך להוסיף את ההגדרות הבאות לחשבון של הפרויקט קובץ build.gradle ברמה העליונה ב-Groovy:

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }