בדיקה מקומית פועלת ישירות בתחנת העבודה שלכם, ולא במכשיר 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 או Truth. קטע הקוד שלמעלה הוא דוגמה לאופן שבו משתמשים ב-junit.Assert
.
ספריית Android שניתן ליצור לה מודלים
כשמריצים בדיקות יחידה מקומיות, Android Gradle Plug-in כולל ספרייה שמכילה את כל ממשקי ה-API של מסגרת Android, בהתאם לגרסה שבה נעשה שימוש בפרויקט. בספרייה נמצאים כל השיטות הציבוריות ה-methods של ממשקי ה-API האלה, אבל הקוד שבתוך השיטות הוסר. אם בכלל של השיטות שניגשים אליהן, הבדיקה גורמת לחריגה.
כך אפשר ליצור בדיקות מקומיות כשמפנינים לכיתות במסגרת Android, כמו Context
. וחשוב יותר, היא מאפשרת להשתמש
את ה-framework עם המחלקות של Android.
הדמיית יחסי תלות של Android
בעיה נפוצה היא גילוי ששימוש במשאב מחרוזת בכיתה. אפשר
לקבל משאבי מחרוזות באמצעות קריאה ל-method getString()
ב-Context
בכיתה. עם זאת, אי אפשר להשתמש ב-Context
או באף אחת מהשיטות שלו בבדיקה מקומית, כי הן שייכות למסגרת של Android. במצב אידיאלי, השיחה אל getString()
תהיה
עברו מהכיתה, אבל לא תמיד זה מעשי. הפתרון הוא ליצור מודל מק"ט או סטאב של Context
שתמיד מחזיר את אותו ערך כשמפעילים את השיטה getString()
שלו.
באמצעות ספריית Mockable Android ופלטפורמות ליצירת מודלים מדומים כמו Mockito או MockK, אפשר לתכנת את ההתנהגות של מודלים מדומים של הכיתות ב-Android בבדיקות היחידה.
כדי להוסיף אובייקט מדומה לבדיקת היחידה המקומית באמצעות Mockito, מבצעים את הפעולות הבאות מודל תכנות:
- כוללים את התלות בספריית Mockito בקובץ
build.gradle
, כפי שמתואר בקטע הגדרת סביבת הבדיקה. - בתחילת ההגדרה של הכיתה בבדיקת היחידה, מוסיפים את הפקודה
הערה אחת (
@RunWith(MockitoJUnitRunner.class)
). ההערה הזו מורה למנהל הבדיקות של Mockito לאמת שהשימוש שלכם במסגרת תקין, ומפשטת את האינטוליזציה של אובייקטי הדמיון. - כדי ליצור אובייקט מדומה של תלות ב-Android, מוסיפים את ההערה
@Mock
לפני הצהרת השדה. - כדי לפגוע בהתנהגות של התלות, אפשר לציין תנאי
של הערך המוחזר כשהתנאי מתקיים באמצעות הפונקציה
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, אפשר לעיין בחומר העזר בנושא Mockito API ובכיתה SharedPreferencesHelperTest
בקוד לדוגמה. כדאי לנסות גם את Codelab בנושא בדיקות ב-Android.
שגיאה: "השיטה ... לא mocked"
ספריית Mockable Android גורמת להפעלת חריגה אם מנסים לגשת לאחת מהשיטות שלה עם ההודעה Error: "Method ... not mocked
.
אם החריגות שמזוהות בעייתיות בבדיקות שלך, אפשר לשנות את
כך ש-methods יחזירו null או אפס, בהתאם
. כדי לעשות זאת, צריך להוסיף את ההגדרות הבאות לחשבון של הפרויקט
קובץ build.gradle
ברמה העליונה ב-Groovy:
android {
...
testOptions {
unitTests.returnDefaultValues = true
}