מעבדת קוד זו היא חלק מהקורס המתקדם של Android בקורס Kotlin. כדי להפיק את המקסימום מהקורס הזה, אם עובדים על מעבדות הקוד ברצף, לא חובה לעשות זאת. כל שיעורי הקוד של הקורסים מופיעים בדף הנחיתה המתקדם של Android ב-Kotlin codelabs.
מבוא
כשהטמעתם את התכונה הראשונה של האפליקציה הראשונה, כנראה הפעלתם את הקוד כדי לוודא שהוא פועל כמצופה. ביצעתם בדיקה, גם אם בדיקה ידנית. ככל שהמשכת להוסיף ולעדכן תכונות, סביר להניח שהמשכת להריץ את הקוד ולאמת שהוא פועל. עם זאת, הדבר נעשה באופן ידני בכל פעם מעייף, חשוף לטעויות ואינו מתרחב.
מחשבים הם יכולת מעולה להתאמה ולאוטומציה! לכן מפתחים בחברות גדולות וקטנות כותבים בדיקות אוטומטיות. אלו הן בדיקות שמופעלות על ידי תוכנה ולא מחייבות אתכם להפעיל את האפליקציה באופן ידני כדי לוודא שהקוד פועל.
בסדרה זו של מעבדות קוד, תלמדו איך ליצור אוסף בדיקות (חבילה לבדיקה) עבור אפליקציה בעולם האמיתי.
מעבדת הקוד הראשונה הזו מכסה את העקרונות הבסיסיים של הבדיקה ב-Android, וכותבים את הבדיקות הראשונות ולומדים איך לבדוק את LiveData
ואת ViewModel
.
דברים שחשוב לדעת
כדאי שתכירו את:
- שפת התכנות Kotlin
- הספריות המרכזיות הבאות של Android Jetpack:
ViewModel
ו-LiveData
- ארכיטקטורת אפליקציות, לפי הדפוסים המפורטים במדריך לארכיטקטורת אפליקציות וב-Android Fundamentals codelabs
מה תלמדו
תוכל ללמוד על הנושאים הבאים:
- איך לכתוב ולהריץ בדיקות יחידה ב-Android
- איך משתמשים בפיתוח מבוסס-בדיקה
- איך לבחור בדיקות אינסטרומנטציה ובדיקות מקומיות
תלמדו על הספריות ועקרונות הקוד הבאים:
הפעולות שתבצעו:
- הגדרה, הפעלה ופרשנות של בדיקות מקומיות ואינסטרומנטציות ב-Android.
- כתיבת בדיקות יחידה ב-Android באמצעות JUNIT4 ו-Hamcrest.
- כתיבה של בדיקות פשוטות ב-
LiveData
וב-ViewModel
.
בסדרה של משימות Lab אלה, אתם תעבדו עם אפליקציית ההערות לביצוע. האפליקציה מאפשרת לכתוב משימות כדי להשלים אותן ולהציג אותן ברשימה. תוכלו לסמן אותם כ'בוצעו' או 'לא בוצעו', לסנן אותם או למחוק אותם.
האפליקציה הזו כתובה ב-Kotlin, יש בה כמה מסכים, משתמשת ברכיבי Jetpack, והיא מבוססת על הארכיטקטורה באמצעות מדריך לארכיטקטורת אפליקציות. אם תבדקו איך לבדוק את האפליקציה הזו, תוכלו לבדוק אפליקציות שמשתמשות באותן ספריות ובארכיטקטורה.
כדי להתחיל, יש להוריד את הקוד:
לחלופין, אפשר לשכפל את מאגר GitHub לקוד:
$ git clone https://github.com/googlecodelabs/android-testing.git $ cd android-testing $ git checkout starter_code
במשימה הזו צריך להריץ את האפליקציה ולגלות את בסיס הקוד.
שלב 1: מריצים את האפליקציה לדוגמה
אחרי שמורידים את האפליקציה 'רשימת משימות', פותחים אותה ב-Android Studio ומפעילים אותה. הוא אמור להידור. כדי לבחון את האפליקציה, מבצעים את הפעולות הבאות:
- יצירת משימה חדשה באמצעות לחצן הפעולה הצף. קודם מזינים כותרת ולאחר מכן מזינים מידע נוסף לגבי המשימה. שומרים אותו עם ההמחאה הירוקה (FAB).
- ברשימת המשימות, לוחצים על השם של המשימה שסיימתם ומעיינים במסך של המשימה כדי לראות את שאר התיאור.
- ברשימה או במסך הפרטים, מסמנים את התיבה של המשימה כדי להגדיר את הסטטוס שלה להושלם.
- חוזרים למסך המשימות, פותחים את תפריט הסינון ומסננים את המשימות לפי הסטטוס פעיל וסטטוס הושלם.
- פותחים את חלונית ההזזה לניווט ולוחצים על נתונים סטטיסטיים.
- חזרה למסך הסקירה הכללית, ובתפריט חלונית ההזזה לניווט, בוחרים באפשרות ניקוי שהושלמו כדי למחוק את כל המשימות עם הסטטוס הושלם.
שלב 2: עיון בקוד האפליקציה לדוגמה
אפליקציית TO-DO מבוססת על דגימת הבדיקה הפופולרית של ארכיטקטורת ארכיטקטורה (באמצעות גרסת הארכיטקטורה רספונסיבית של הדוגמה). האפליקציה בנויה לפי הארכיטקטורה במדריך לארכיטקטורת אפליקציות. המודל משתמש ב-ViewModel עם Fragments, מאגר וחדר. אם אתם מכירים את אחת מהדוגמאות הבאות, לאפליקציה הזו יש ארכיטקטורה דומה:
- חדר עם View Code Lab
- מעבדות קוד הדרכה ל-Android Kotlin Fundamentals
- שיעורי Lab להדרכה ב-Android
- דוגמה ל-Android החמנייה
- פיתוח אפליקציות ל-Android באמצעות קורס ההדרכה של Kotlin Udacity
חשוב יותר להבין את הארכיטקטורה הכללית של האפליקציה מאשר להבין לעומק את הלוגיקה בכל שכבה.
זהו סיכום החבילות שתמצא:
חבילה: | |
| הוספה או עריכה של מסך משימה: קוד שכבה של ממשק משתמש להוספה או לעריכה של משימה. |
| שכבת הנתונים: פעולה זו מתאימה לשכבת הנתונים של המשימות. הם כוללים את מסד הנתונים, הרשת וקוד המאגר. |
| מסך הנתונים הסטטיסטיים: קוד שכבה של ממשק משתמש למסך הנתונים הסטטיסטיים. |
| מסך פרטי המשימה: קוד שכבה של ממשק משתמש למשימה אחת. |
| מסך המשימות: קוד שכבת ממשק המשתמש עבור הרשימה של כל המשימות. |
| שיעורי עזר: כיתות משותפות המשמשות בחלקים שונים של האפליקציה. למשל, פריסת ההחלקה המשמשת במספר מסכים. |
שכבת נתונים (.data)
אפליקציה זו כוללת סימולציה של שכבת רשת, בחבילה שלט רחוק, ושכבת מסד נתונים בחבילה מקומית. כדי לפשט את הדברים, בפרויקט הזה מתבצעת סימולציה של שכבת הרשת עם HashMap
בלבד, עם עיכוב במקום ביצוע בקשות אמיתיות ברשת.
הקואורדינטות של DefaultTasksRepository
מתווכות או מתווכות בין שכבת הרשת לבין שכבת מסד הנתונים, והיא זו שמחזירה נתונים לשכבת ממשק המשתמש.
שכבת ממשק משתמש ( .addedittask, .statistics, .taskdetail, .tasks)
כל אחת מהחבילות של שכבות ממשק המשתמש מכילה מקטע ומודל תצוגה, וכן כיתות אחרות הנדרשות עבור ממשק המשתמש (כגון מתאם עבור רשימת המשימות). הTaskActivity
הוא הפעילות שמכילה את כל הקטעים.
ניווט
הניווט באפליקציה נשלט על ידי רכיב הניווט. הוא מוגדר בקובץ nav_graph.xml
. הניווט מופעל במודלים של תצוגות מפורטות באמצעות הכיתה Event
; המודלים של התצוגה קובעים גם אילו ארגומנטים יעברו. המקטעים מעיינים ב-Event
ומבצעים את הניווט בפועל בין מסכים.
במשימה הזו, מריצים את הבדיקות הראשונות.
- ב-Android Studio, פותחים את החלונית Project (פרויקט) ומוצאים את שלוש התיקיות הבאות:
com.example.android.architecture.blueprints.todoapp
com.example.android.architecture.blueprints.todoapp (androidTest)
com.example.android.architecture.blueprints.todoapp (test)
תיקיות אלה נקראות קבוצות מקור. קבוצות המקור הן תיקיות שמכילות קוד מקור של האפליקציה. קבוצות המקור, שהן צבעים ירוקים (androidTest ו-test), מכילות את הבדיקות שלך. כשיוצרים פרויקט חדש ל-Android, כברירת מחדל מוצגות 3 קבוצות המקורות הבאות. אלו הם:
main
: מכיל את קוד האפליקציה שלכם. הקוד הזה משותף לכל הגרסאות השונות של האפליקציה שאפשר ליצור (שנקרא גרסאות Build)androidTest
: מכיל בדיקות המוכרות כאינסטרומנטציות.test
: מכילה בדיקות שנקראות בדיקות מקומיות.
ההבדל בין בדיקות מקומיות לבין בדיקות אינסטרומנטליות הוא הדרך שבה הן מתבצעות.
בדיקות מקומיות (test
קבוצת המקור)
הבדיקות האלה מבוצעות באופן מקומי במכונת ה-JVM של המכונה שלך, והן לא מחייבות אמולטור או מכשיר פיזי. לכן, הם פועלים במהירות, אבל האיכות שלהם נמוכה יותר, כלומר הם פועלים פחות מאשר בעולם האמיתי.
בבדיקות מקומיות של Android Studio מיוצגים סמל של משולש ירוק ואדום.
בדיקות מתוכננות (androidTest
קבוצת המקור)
הבדיקות האלה פועלות במכשירי Android אמיתיים או אמולטורים, כך שהן משקפות את מה שיקרה בעולם האמיתי, אבל גם הן איטיות הרבה יותר.
ב-Android Studio, אינסטרומנטציות שהן מיוצגות מיוצגות על ידי Android עם סמל משולש בצבעי ירוק ואדום.
שלב 1: מפעילים בדיקה מקומית
- פותחים את התיקייה
test
עד שמופיע הקובץ ExampleUnitTest.kt. - לוחצים עליה לחיצה ימנית ובוחרים באפשרות Run ExampleUnitTest.
הפלט הבא אמור להופיע בחלון Run בתחתית המסך:
- שימו לב לנקודות הסימון הירוקות והרחיבו את תוצאות הבדיקה כדי לוודא שבדיקה אחת בשם
addition_isCorrect
עברה. אנחנו יודעים שתוספת זו פועלת כמצופה!
שלב 2: ביצוע הבדיקה נכשל
זו הבדיקה שהרצתם עכשיו.
ExampleItemTest.kt
// A test class is just a normal class
class ExampleUnitTest {
// Each test is annotated with @Test (this is a Junit annotation)
@Test
fun addition_isCorrect() {
// Here you are checking that 4 is the same as 2+2
assertEquals(4, 2 + 2)
}
}
חשוב לשים לב שבדיקות
- הם כיתה באחת מהקבוצות של מקורות הבדיקה.
- מכילים פונקציות שמתחילות בהערה
@Test
(כל פונקציה היא בדיקה יחידה). - מכילים באופן אוטומטי הצהרות בעלות.
Android משתמש בספריית הבדיקה JUNIT לבדיקה (בקוד זה LabJ4). שתי הטענות וההערה @Test
מגיעות מ-JUNIT.
בדיקה היא הבסיס לבדיקה. זוהי הצהרת קוד שבודקת שהקוד או האפליקציה התנהגו כצפוי. במקרה זה, הקביעה היא assertEquals(4, 2 + 2)
שבודקת ש-4 שווה ל-2 + 2.
כדי לראות איך נראית בדיקה שנכשלה, יש להוסיף הצהרה שאפשר לראות בקלות. צריך לבדוק ש-3 הוא 1+1.
- עליך להוסיף את
assertEquals(3, 1 + 1)
לבדיקה שלaddition_isCorrect
.
ExampleItemTest.kt
class ExampleUnitTest {
// Each test is annotated with @Test (this is a Junit annotation)
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
assertEquals(3, 1 + 1) // This should fail
}
}
- מריצים את הבדיקה.
- בתוצאות הבדיקה, מסמנים את ה-X ליד הבדיקה.
- כמו כן:
- טענה אחת שנכשלה נכשלה בכל הבדיקה.
- אתם מקבלים את הערך הצפוי (3) לעומת הערך שחושב בפועל (2).
- הופנתה אל שורת הטענה שנכשלה
(ExampleUnitTest.kt:16)
.
שלב 3: מפעילים בדיקה של אינסטרומנטציה
בדיקות שעברו אינסטרומנטציה נמצאות בקבוצת המקורות של androidTest
.
- פותחים את קבוצת המקור של
androidTest
. - מריצים את הבדיקה שנקראת
ExampleInstrumentedTest
.
ExampleSampleedTest
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.android.architecture.blueprints.reactive",
appContext.packageName)
}
}
בשונה מהבדיקה המקומית, הבדיקה הזו פועלת במכשיר (בדוגמה שמתחת לטלפון אמולציה של Pixel 2):
אם יש לך מכשיר מחובר או אמולטור פועל, הבדיקה אמורה להופיע על האמולטור.
במשימה הזו עליך לכתוב בדיקות עבור getActiveAndCompleteStats
, שמחשבות את אחוז הנתונים הסטטיסטיים הפעילים והמלאים של המשימות באפליקציה שלך. אפשר לראות את המספרים האלה במסך הנתונים הסטטיסטיים של האפליקציה.
שלב 1: יצירת כיתת בדיקה
- בקבוצת המקור של
main
, ב-todoapp.statistics
, פותחים אתStatisticsUtils.kt
. - מוצאים את הפונקציה
getActiveAndCompletedStats
.
StatistsUillas.kt
internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {
val totalTasks = tasks!!.size
val numberOfActiveTasks = tasks.count { it.isActive }
val activePercent = 100 * numberOfActiveTasks / totalTasks
val completePercent = 100 * (totalTasks - numberOfActiveTasks) / totalTasks
return StatsResult(
activeTasksPercent = activePercent.toFloat(),
completedTasksPercent = completePercent.toFloat()
)
}
data class StatsResult(val activeTasksPercent: Float, val completedTasksPercent: Float)
הפונקציה getActiveAndCompletedStats
מקבלת רשימה של משימות ומחזירה StatsResult
. StatsResult
הוא סיווג נתונים שמכיל שני מספרים, אחוז המשימות שהושלמו ואחוז הפעיל.
ב-Android Studio אפשר למצוא כלים ליצירת כלים נלווים לבדיקה עבור הפונקציה הזו.
- לוחצים לחיצה ימנית על
getActiveAndCompletedStats
ובוחרים באפשרות Generate > Test.
תיבת הדו-שיח Create Test תיפתח:
- משנים את שם הכיתה: ל-
StatisticsUtilsTest
(במקוםStatisticsUtilsKtTest
; עדיף שלא יהיה KT בשם הכיתה לבדיקה). - משאירים את ברירות המחדל האחרות. ספריית יחידה 4 היא ספריית הבדיקה המתאימה. חבילת היעד נכונה (היא משקפת את המיקום של מחלקת
StatisticsUtils
) ואין צורך לסמן אף אחת מתיבות הסימון (פעולה זו יוצרת קוד נוסף, אך לכתוב את הבדיקה מאפס). - מקישים על אישור
תיבת הדו-שיח בחירת ספריית יעד תיפתח:
תבצע בדיקה מקומית כי הפונקציה מבצעת חישובים מתמטיים והיא לא תכלול קוד ספציפי של Android. לכן אין צורך להפעיל אותו במכשיר אמיתי או אמולציה.
- יש לבחור את הספרייה
test
(ולאandroidTest
) כי צריך לכתוב בדיקות מקומיות. - לוחצים על אישור.
- שימו לב לכיתה
StatisticsUtilsTest
שנוצרה ב-test/statistics/
.
שלב 2: כתיבה של פונקציית הבדיקה הראשונה
אתם כותבים בדיקה שבודקת את הדברים הבאים:
- אם אין משימות שהושלמו ומשימה פעילה אחת,
- שאחוז הבדיקות הפעילות הוא 100%,
- ואחוז המשימות שבוצעו הוא 0%.
- פתיחת
StatisticsUtilsTest
- צריך ליצור פונקציה בשם
getActiveAndCompletedStats_noCompleted_returnsHundredZero
.
StatistsUillasTest.kt
class StatisticsUtilsTest {
fun getActiveAndCompletedStats_noCompleted_returnsHundredZero() {
// Create an active task
// Call your function
// Check the result
}
}
- מוסיפים את ההערה
@Test
מעל שם הפונקציה כדי לציין שמדובר בבדיקה. - יצירה של רשימת משימות.
// Create an active task
val tasks = listOf<Task>(
Task("title", "desc", isCompleted = false)
)
- התקשרות אל
getActiveAndCompletedStats
לביצוע המשימות האלה.
// Call your function
val result = getActiveAndCompletedStats(tasks)
- יש לוודא ש-
result
הוא מה שציפית לקבל, באמצעות טענות.
// Check the result
assertEquals(result.completedTasksPercent, 0f)
assertEquals(result.activeTasksPercent, 100f)
זה הקוד המלא.
StatistsUillasTest.kt
class StatisticsUtilsTest {
@Test
fun getActiveAndCompletedStats_noCompleted_returnsHundredZero() {
// Create an active task (the false makes this active)
val tasks = listOf<Task>(
Task("title", "desc", isCompleted = false)
)
// Call your function
val result = getActiveAndCompletedStats(tasks)
// Check the result
assertEquals(result.completedTasksPercent, 0f)
assertEquals(result.activeTasksPercent, 100f)
}
}
- מריצים את הבדיקה (לוחצים לחיצה ימנית על
StatisticsUtilsTest
ובוחרים באפשרות הפעלה).
עליה לעבור:
שלב 3: מוסיפים את התלות של המארקסט
הבדיקות שלך פועלות כתיעוד של מה שהקוד שלך עושה, לכן זה נעים כאשר הן ניתנות לקריאה על ידי אנשים. משווים בין שתי הטענות הבאות:
assertEquals(result.completedTasksPercent, 0f)
// versus
assertThat(result.completedTasksPercent, `is`(0f))
הקביעה השנייה נראית הרבה יותר כמו משפט אנושי. היא נכתבת באמצעות מסגרת הצהרת בשם Hamcrest. כלי טוב נוסף לכתיבת טענות שניתן לקרוא אותן הוא ספריית המציאות. תשתמשו בהאמרס במעבדה הזו כדי לכתוב טענות.
- יש לפתוח את
build.grade (Module: app)
ולהוסיף את התלויות הבאות.
app/build.gradle
dependencies {
// Other dependencies
testImplementation "org.hamcrest:hamcrest-all:$hamcrestVersion"
}
בדרך כלל, נעשה שימוש ב-implementation
כשמוסיפים תלות, אבל כן נעשה שימוש במאפיין testImplementation
. כאשר אתם מוכנים לשתף את האפליקציה שלכם עם העולם, מומלץ לא להגדיל את כמות ה-APK באמצעות קוד הבדיקה או תלויים באפליקציה שלכם. אפשר לקבוע אם ספרייה תכלל בקוד הראשי או בקוד הבדיקה באמצעות הגדרות דרגה. ההגדרות הנפוצות ביותר הן:
implementation
—התלות זמינה בכל קבוצות המקור, כולל קבוצות המקור של הבדיקה.testImplementation
– התלויה זמינה רק בקבוצת המקור של הבדיקה.androidTestImplementation
— התלות זמינה רק בקבוצת המקור ב-androidTest
.
ההגדרה שבה משתמשים תלויה במקום שבו ניתן להשתמש. אם כותבים:
testImplementation "org.hamcrest:hamcrest-all:$hamcrestVersion"
משמעות הדבר היא שהמרסקט יהיה זמין רק בקבוצת מקורות הבדיקה. היא גם מבטיחה שהאמסטר לא ייכלל באפליקציה הסופית שלכם.
שלב 4: כתיבת טענות באמצעות האמברסט
- יש לעדכן את הבדיקה של
getActiveAndCompletedStats_noCompleted_returnsHundredZero()
כדי להשתמש ב-assertThat
של Humcrest במקום ב-assertEquals
.
// REPLACE
assertEquals(result.completedTasksPercent, 0f)
assertEquals(result.activeTasksPercent, 100f)
// WITH
assertThat(result.activeTasksPercent, `is`(100f))
assertThat(result.completedTasksPercent, `is`(0f))
לתשומת ליבך, אפשר להשתמש בייבוא של import org.hamcrest.Matchers.`is`
אם מתבקשים לעשות זאת.
הבדיקה הסופית נראית כמו הקוד הבא.
StatistsUillasTest.kt
import com.example.android.architecture.blueprints.todoapp.data.Task
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.`is`
import org.junit.Test
class StatisticsUtilsTest {
@Test
fun getActiveAndCompletedStats_noCompleted_returnsHundredZero {
// Create an active tasks (the false makes this active)
val tasks = listOf<Task>(
Task("title", "desc", isCompleted = false)
)
// Call your function
val result = getActiveAndCompletedStats(tasks)
// Check the result
assertThat(result.activeTasksPercent, `is`(100f))
assertThat(result.completedTasksPercent, `is`(0f))
}
}
- כדאי להריץ את הבדיקה המעודכנת כדי לוודא שהיא עדיין פועלת.
Codelab זה לא ילמד את כל הפרטים בחמרס, אם אתם רוצים לקבל מידע נוסף תוכלו לעיין במדריך הרשמי.
זוהי משימה אופציונלית שאפשר לתרגל.
במשימה הזו צריך לכתוב עוד בדיקות באמצעות JUNIT והמארקסט. צריך גם לכתוב בדיקות באמצעות שיטה שנגזרת מתוכנית התוכנית של פיתוח מבוסס בדיקות. 'פיתוח מבוסס בדיקה' או TDD הוא בית ספר לתכנות, אשר אומר במקום לכתוב את קוד התכונה שלכם קודם כל, עליכם לכתוב תחילה את הבדיקות. לאחר מכן, כותבים את קוד התכונה במטרה לעבור את הבדיקות.
שלב 1. כתיבת הבדיקות
כתיבת בדיקות למקרה שיש לכם רשימת משימות רגילה:
- אם יש משימה אחת שהושלמה ולא בוצעו משימות פעילות, האחוז באחוזים של
activeTasks
צריך להיות0f
ואחוז המשימות שבוצעו צריך להיות100f
. - אם יש שתי משימות שבוצעו ושלוש משימות פעילות, האחוז צריך להיות
40f
והאחוז הפעיל צריך להיות60f
.
שלב 2. כתיבת בדיקה לבאג
הקוד של getActiveAndCompletedStats
כפי שהוא מופיע מופיע באג. הערה: היא לא מטפלת כראוי במה שקורה אם הרשימה ריקה או ריקה. בשני המקרים האלה, שני האחוזים צריכים להיות אפס.
internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {
val totalTasks = tasks!!.size
val numberOfActiveTasks = tasks.count { it.isActive }
val activePercent = 100 * numberOfActiveTasks / totalTasks
val completePercent = 100 * (totalTasks - numberOfActiveTasks) / totalTasks
return StatsResult(
activeTasksPercent = activePercent.toFloat(),
completedTasksPercent = completePercent.toFloat()
)
}
כדי לתקן את הקוד ולכתוב בדיקות, עליכם להשתמש בפיתוח מבוסס-בדיקות. פיתוח מבוסס-בדיקה פועל לפי השלבים הבאים.
- יש לכתוב את הבדיקה באמצעות המבנה לשם, מתי ואז, ולציין שם בהתאם למוסכמות.
- מוודאים שהבדיקה נכשלה.
- יש להזין את הקוד המינימלי כדי לעבור את הבדיקה.
- חוזרים על הפעולה עבור כל הבדיקות.
במקום להתחיל על ידי תיקון הבאג, קודם כל צריך לכתוב את הבדיקות. לאחר מכן, תוכלו לאשר שיש לכם בדיקות שמגינות עליכם מפני הוספה חוזרת של באגים בעתיד.
- אם יש רשימה ריקה (
emptyList()
), שני האחוזים צריכים להיות 0f. - אם אירעה שגיאה בטעינת המשימות, הרשימה תהיה
null
והשניים צריכים להיות 0f. - מריצים את הבדיקות ומוודאים שהם נכשלים:
שלב 3. תיקון הבאג
עכשיו, אחרי שהתבצעה הבדיקה, יש לתקן את הבאג.
- יש להחזיר את הבאג בכתובת
getActiveAndCompletedStats
על ידי החזרת הערך0f
אם הערך שלtasks
הואnull
או ריק:
internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {
return if (tasks == null || tasks.isEmpty()) {
StatsResult(0f, 0f)
} else {
val totalTasks = tasks.size
val numberOfActiveTasks = tasks.count { it.isActive }
StatsResult(
activeTasksPercent = 100f * numberOfActiveTasks / tasks.size,
completedTasksPercent = 100f * (totalTasks - numberOfActiveTasks) / tasks.size
)
}
}
- הפעילו שוב את הבדיקות וודאו שכל הבדיקות עברו בהצלחה.
על ידי המשך הטיפול ב-TDD וכתיבת הבדיקות, עזרת לוודא:
- לפונקציונליות חדשה תמיד משויכות בדיקות. לכן, הבדיקות משפיעות על התיעוד של הקוד.
- הבדיקות בודקות את התוצאות הנכונות ומגנה מפני באגים שכבר ראית.
פתרון: כתיבת בדיקות נוספות
אלה כל הבדיקות וקוד התכונה המתאים.
StatistsUillasTest.kt
class StatisticsUtilsTest {
@Test
fun getActiveAndCompletedStats_noCompleted_returnsHundredZero {
val tasks = listOf(
Task("title", "desc", isCompleted = false)
)
// When the list of tasks is computed with an active task
val result = getActiveAndCompletedStats(tasks)
// Then the percentages are 100 and 0
assertThat(result.activeTasksPercent, `is`(100f))
assertThat(result.completedTasksPercent, `is`(0f))
}
@Test
fun getActiveAndCompletedStats_noActive_returnsZeroHundred() {
val tasks = listOf(
Task("title", "desc", isCompleted = true)
)
// When the list of tasks is computed with a completed task
val result = getActiveAndCompletedStats(tasks)
// Then the percentages are 0 and 100
assertThat(result.activeTasksPercent, `is`(0f))
assertThat(result.completedTasksPercent, `is`(100f))
}
@Test
fun getActiveAndCompletedStats_both_returnsFortySixty() {
// Given 3 completed tasks and 2 active tasks
val tasks = listOf(
Task("title", "desc", isCompleted = true),
Task("title", "desc", isCompleted = true),
Task("title", "desc", isCompleted = true),
Task("title", "desc", isCompleted = false),
Task("title", "desc", isCompleted = false)
)
// When the list of tasks is computed
val result = getActiveAndCompletedStats(tasks)
// Then the result is 40-60
assertThat(result.activeTasksPercent, `is`(40f))
assertThat(result.completedTasksPercent, `is`(60f))
}
@Test
fun getActiveAndCompletedStats_error_returnsZeros() {
// When there's an error loading stats
val result = getActiveAndCompletedStats(null)
// Both active and completed tasks are 0
assertThat(result.activeTasksPercent, `is`(0f))
assertThat(result.completedTasksPercent, `is`(0f))
}
@Test
fun getActiveAndCompletedStats_empty_returnsZeros() {
// When there are no tasks
val result = getActiveAndCompletedStats(emptyList())
// Both active and completed tasks are 0
assertThat(result.activeTasksPercent, `is`(0f))
assertThat(result.completedTasksPercent, `is`(0f))
}
}
StatistsUillas.kt
internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {
return if (tasks == null || tasks.isEmpty()) {
StatsResult(0f, 0f)
} else {
val totalTasks = tasks.size
val numberOfActiveTasks = tasks.count { it.isActive }
StatsResult(
activeTasksPercent = 100f * numberOfActiveTasks / tasks.size,
completedTasksPercent = 100f * (totalTasks - numberOfActiveTasks) / tasks.size
)
}
}
עבודה טובה עם היסודות של כתיבה והפעלה של בדיקות! בשלב הבא עליך ללמוד איך לכתוב בדיקות בסיסיות של ViewModel
ושל LiveData
.
בשאר תכונות שיעור הקוד תלמדו איך לכתוב בדיקות לשתי כיתות נפוצות ב-Android, ברוב האפליקציות — ViewModel
ו-LiveData
.
אפשר להתחיל בכתיבת בדיקות עבור TasksViewModel
.
אתם תתמקדו בבדיקות שכוללות את הלוגיקה שלהן במודל התצוגה המפורטת ולא מסתמכות על קוד מאגר. קוד המאגר כולל קוד אסינכרוני, מסדי נתונים וקריאות לרשת. כל הנתונים האלה מוסיפים למורכבות של הבדיקה. בינתיים כדאי להימנע מכך, ולהתמקד בכתיבת בדיקות לפונקציונליות של ViewModel שאינה בודקת ישירות שום דבר במאגר.
הבדיקה שתכתבו תוודא שכשתתקשרו לשיטה addNewTask
, תופעל Event
של פתיחת חלון המשימה החדש. זהו קוד האפליקציה שאותו תבדקו.
TasksViewModel.kt
fun addNewTask() {
_newTaskEvent.value = Event(Unit)
}
שלב 1. יצירת כיתה של TasksViewModelTest
מבצעים את אותם השלבים שביצעת ל-StatisticsUtilTest
בשלב הזה ויוצרים קובץ בדיקה עבור TasksViewModelTest
.
- פותחים את הכיתה שרוצים לבדוק בחבילה
tasks
,TasksViewModel.
. - לוחצים לחיצה ימנית על שם הכיתה
TasksViewModel
– > Generate -> Test.
- במסך יצירת בדיקה, לוחצים על אישור כדי לאשר (אין צורך לשנות את הגדרות ברירת המחדל).
- בתיבת הדו-שיח Choose Directory Directory, בוחרים את ספריית הבדיקה.
שלב 2. מתחילים לכתוב את בדיקת ה-ViewModel
בשלב זה מוסיפים בדיקה של מודל תצוגה כדי לבדוק שכשמתקשרים בשיטה addNewTask
, הפונקציה Event
לפתיחת חלון המשימה החדש מופעלת.
- יצירת בדיקה חדשה בשם
addNewTask_setsNewTaskEvent
TasksViewModelTest.kt
class TasksViewModelTest {
@Test
fun addNewTask_setsNewTaskEvent() {
// Given a fresh TasksViewModel
// When adding a new task
// Then the new task event is triggered
}
}
מה לגבי הקשר לאפליקציה?
כשיוצרים מופע של TasksViewModel
לבדיקה, ה-constructor שלו דורש הקשר של אפליקציה. אבל בבדיקה הזו, אתם לא יוצרים אפליקציה מלאה עם פעילויות וממשק משתמש ועם מקטעים, אז איך מקבלים הקשר של אפליקציה?
TasksViewModelTest.kt
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(???)
ספריות הבדיקה של AndroidX כוללות קורסים ושיטות שמספקים גרסאות של אפליקציות כמו אפליקציות ופעילויות שמיועדות לבדיקות. כשמבצעים בדיקה מקומית שבה יש צורך בכיתות סימולציה של Android (כמו הקשר של אפליקציה), כדי להגדיר כראוי בדיקה של AndroidX:
- הוספת הליבה של AndroidX Testing והתלויות החיצוניות
- הוספת תלות בספריית הבדיקות של Robolectric
- הוספת הערה לכיתה באמצעות הרצת הבדיקה של AndroidJunit4
- כתיבת קוד בדיקה של AndroidX
אתם עומדים לבצע את השלבים האלה, ואז להבין מה הם עושים ביחד.
שלב 3. הוספת תלויות הציונים
- אפשר להעתיק את התלות האלה בקובץ
build.gradle
של מודול האפליקציה & כדי להוסיף את הליבה הליבה של AndroidX והתלויות, וכן את התלות של בדיקות ה-Robolectric.
app/build.gradle
// AndroidX Test - JVM testing
testImplementation "androidx.test.ext:junit-ktx:$androidXTestExtKotlinRunnerVersion"
testImplementation "androidx.test:core-ktx:$androidXTestCoreVersion"
testImplementation "org.robolectric:robolectric:$robolectricVersion"
שלב 4. הוספת מריץ בדיקה של JUNIT
- יש להוסיף את
@RunWith(AndroidJUnit4::class)
מעל לכיתת הבדיקה.
TasksViewModelTest.kt
@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {
// Test code
}
שלב 5. שימוש בבדיקת AndroidX
בשלב הזה אפשר להשתמש בספריית הבדיקה של AndroidX. כולל השיטה ApplicationProvider.getApplicationContex
t
, שמקבלת הקשר לאפליקציה.
- אפשר ליצור
TasksViewModel
באמצעותApplicationProvider.getApplicationContext()
מספריית הבדיקה של AndroidX.
TasksViewModelTest.kt
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
- התקשרות אל
addNewTask
בtasksViewModel
.
TasksViewModelTest.kt
tasksViewModel.addNewTask()
בשלב זה, הבדיקה שלך אמורה להיראות כמו הקוד הבא.
TasksViewModelTest.kt
@Test
fun addNewTask_setsNewTaskEvent() {
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
// When adding a new task
tasksViewModel.addNewTask()
// Then the new task event is triggered
// TODO test LiveData
}
- מריצים את הבדיקה כדי לוודא שהיא פועלת.
קונספט: איך פועל בדיקת XX ב-Android?
מהי בדיקת XX?
AndroidX Test הוא אוסף של ספריות לבדיקה. הן כוללות קורסים ושיטות שמאפשרות גרסאות של אפליקציות, כמו אפליקציות ופעילויות, שמטרתן לבצע בדיקות. לדוגמה, הקוד הזה הוא דוגמה לפונקציית בדיקה של AndroidX לקבלת הקשר לאפליקציה.
ApplicationProvider.getApplicationContext()
אחד היתרונות של ה-APIs של בדיקת AndroidX הוא שהם מיועדים לעבוד גם בבדיקות מקומיות וגם בבדיקות אינסטרומנטליות. זה נהדר כי:
- אפשר להריץ את אותה בדיקה כמו בדיקה מקומית או בדיקת אינסטרומנטציה.
- אין צורך ללמוד ממשקי API שונים לבדיקות של בדיקות מקומיות לעומת בדיקות אינסטרומנטליות.
לדוגמה, כי כתבת את הקוד באמצעות ספריות בדיקה של AndroidX, אפשר להעביר את הכיתה TasksViewModelTest
מהתיקייה test
לתיקייה androidTest
, והבדיקות עדיין יפעלו. getApplicationContext()
פועל באופן שונה מעט אם הוא פועל כבדיקה מקומית או כאינסטרומנטציה:
- אם מדובר בבדיקת אינסטרומנטציה, היא מקבלת את ההקשר האמיתי של השימוש באפליקציה כשהיא מפעילה את האמולטור או מתחבר למכשיר אמיתי.
- אם מדובר בבדיקה מקומית, היא משתמשת בסביבת סימולציה של Android.
מה זה Robolectric?
סימולציה של סביבת Android המשמשת לבדיקות מקומיות היא באמצעות Robolectric. Robolectric היא ספרייה שיוצרת סביבת Android מדומה לצורך בדיקות ופועלת מהר יותר מאתחול אמולטור או הפעלה במכשיר. ללא התלות ב-Robolectric, תתקבל השגיאה הזו:
מה יקרה @RunWith(AndroidJUnit4::class)
?
הפעלת בדיקה היא רכיב Junit שמפעיל בדיקות. ללא ראנר בדיקה, הבדיקות שלכם לא יפעלו. יש הרצת ברירת מחדל לבדיקה ש-JUNIT מקבל באופן אוטומטי. @RunWith
תחליף את הרצת הבדיקה המוגדרת כברירת מחדל.
הרצת הבדיקה AndroidJUnit4
מאפשרת ל-AndroidX Testing להריץ את הבדיקה בצורה שונה, בהתאם לסוג הבדיקות: אינסטרומנטציה או בדיקות מקומיות.
שלב 6. תיקון אזהרות Robolectric
כשאתם מריצים את הקוד, שימו לב שנעשה שימוש ב-Robolectric.
בזכות בדיקת ה-AndroidX והרצפת הבדיקה של AndroidJunit4, אנחנו עושים זאת בלי לכתוב ישירות שורה אחת של קוד Robolectric!
ייתכן שיופיעו שתי אזהרות.
No such manifest file: ./AndroidManifest.xml
"WARN: Android SDK 29 requires Java 9..."
אפשר לעדכן את אזהרת No such manifest file: ./AndroidManifest.xml
כדי לעדכן את קובץ הציונים.
- יש להוסיף את השורה הבאה לקובץ הציונים כדי להשתמש במניפסט הנכון ב-Android. האפשרות includeAndroidResources מאפשרת לך לגשת למשאבי Android בבדיקות היחידות, כולל קובץ AndroidManifest.
app/build.gradle
// Always show the result of every unit test when running via command line, even if it passes.
testOptions.unitTests {
includeAndroidResources = true
// ...
}
האזהרה "WARN: Android SDK 29 requires Java 9..."
מורכבת יותר. כדי לבצע בדיקות ב-Android Q יש צורך ב-Java 9. במקום לנסות להגדיר את Android להשתמש ב-Java 9, ב-codelab זה צריך לשמור על היעד ולהדר את SDK ב-28.
לסיכום:
- לרוב, בדיקות של מודל תצוגה מפורטת יכולות להתבצע בקבוצת המקור
test
, כי הקוד שלהן לא נדרש בדרך כלל עם Android. - אפשר להשתמש בבדיקת AndroidX הספרייה כדי לקבל גרסאות בדיקה של רכיבים כמו אפליקציות ופעילויות.
- כדי להפעיל סימולציה של קוד Android בקבוצת המקורות של
test
, אפשר להוסיף את התלות ב-Robolectric ואת ההערה עם@RunWith(AndroidJUnit4::class)
.
מזל טוב, אתם משתמשים בספריית הבדיקה של AndroidX וגם ב-Robolectric כדי להריץ בדיקה. הבדיקה שלך לא הסתיימה (עדיין לא כתבת הצהרה בבית, אבל היא אומרת רק // TODO test LiveData
). מעכשיו עליך לכתוב הצהרות עם LiveData
.
במשימה הזו מוסבר איך להצהיר על ערך LiveData
נכון.
רוצה להמשיך בלי בדיקת מודל של addNewTask_setsNewTaskEvent
כדי לראות מהמקום שבו הפסקת?
TasksViewModelTest.kt
@Test
fun addNewTask_setsNewTaskEvent() {
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
// When adding a new task
tasksViewModel.addNewTask()
// Then the new task event is triggered
// TODO test LiveData
}
כדי לבדוק את LiveData
מומלץ לבצע שתי פעולות:
- שימוש באפליקציה
InstantTaskExecutorRule
- יש לוודא שתצפית אחת (
LiveData
)
שלב 1. שימוש ב- InstantTaskExecutorRule
InstantTaskExecutorRule
הוא כלל JUNIT. אם מזינים את ההערה הזו עם ההערה @get:Rule
, היא גורמת להפעלת קוד כלשהו בכיתה InstantTaskExecutorRule
לפני ואחרי הבדיקות (כדי לראות את הקוד המדויק, אפשר להשתמש במקש הקיצור Command+B כדי להציג את הקובץ).
כלל זה מפעיל את כל עבודות הרקע הקשורות לרכיבי ארכיטקטורה באותו שרשור, כדי שתוצאות הבדיקה יתרחשו באופן סינכרוני ובסדר חוזר. כשכותבים בדיקות שכוללות בדיקה של LiveData, אפשר להשתמש בכלל הזה!
- מוסיפים את התלות בהיררכיה של ספריית הליבה של רכיבי הארכיטקטורה (שכוללת את הכלל הזה).
app/build.gradle
testImplementation "androidx.arch.core:core-testing:$archTestingVersion"
- פתיחה של
TasksViewModelTest.kt
- הוספה של
InstantTaskExecutorRule
בתוך המחלקהTasksViewModelTest
.
TasksViewModelTest.kt
class TasksViewModelTest {
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
// Other code...
}
שלב 2. הוספת ה-LiveDataTestUilla.kt Class
השלב הבא הוא לוודא שהבדיקה של LiveData
מתבצעת.
כשאתם משתמשים ב-LiveData
, בדרך כלל יש לכם פעילות או מקטע (LifecycleOwner
) שצופים ב-LiveData
.
viewModel.resultLiveData.observe(fragment, Observer {
// Observer code here
})
התצפית הזו חשובה. נדרשים צופים פעילים ב-LiveData
כדי
- להפעיל אירועים מסוג
onChanged
. - מפעילים כל המרה.
כדי לקבל את ההתנהגות LiveData
הצפויה עבור מודל התצוגה המפורטת 'LiveData
', עליך לצפות ב-LiveData
עם LifecycleOwner
.
פעולה זו יוצרת בעיה: בבדיקה של TasksViewModel
אין לך פעילות או שבר שתצפית על LiveData
שלך. כדי לעקוף את הבעיה, אפשר להשתמש בשיטה observeForever
, שבעזרתה אפשר לעקוב באופן קבוע אחרי LiveData
, בלי צורך ב-LifecycleOwner
. כשאתם observeForever
, חשוב לזכור להסיר את הצופה או להסתכן בדליפת צופים.
זה נראה כמו הקוד הבא. בדיקה של:
@Test
fun addNewTask_setsNewTaskEvent() {
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
// Create observer - no need for it to do anything!
val observer = Observer<Event<Unit>> {}
try {
// Observe the LiveData forever
tasksViewModel.newTaskEvent.observeForever(observer)
// When adding a new task
tasksViewModel.addNewTask()
// Then the new task event is triggered
val value = tasksViewModel.newTaskEvent.value
assertThat(value?.getContentIfNotHandled(), (not(nullValue())))
} finally {
// Whatever happens, don't forget to remove the observer!
tasksViewModel.newTaskEvent.removeObserver(observer)
}
}
זה הרבה קוד בישול כדי להבחין בLiveData
של בדיקה! יש כמה דרכים להיפטר מהבורה הזו. בחרת ליצור פונקציית תוסף בשם LiveDataTestUtil
כדי להקל על הוספת צופים.
- יצירת קובץ Kotlin חדש בשם
LiveDataTestUtil.kt
בקבוצת המקור שלtest
.
- מעתיקים את הקוד ומדביקים אותו למטה.
LiveDataTestUטרי.kt
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun <T> LiveData<T>.getOrAwaitValue(
time: Long = 2,
timeUnit: TimeUnit = TimeUnit.SECONDS,
afterObserve: () -> Unit = {}
): T {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
this@getOrAwaitValue.removeObserver(this)
}
}
this.observeForever(observer)
try {
afterObserve.invoke()
// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
throw TimeoutException("LiveData value was never set.")
}
} finally {
this.removeObserver(observer)
}
@Suppress("UNCHECKED_CAST")
return data as T
}
זוהי שיטה מורכבת למדי. היא יוצרת פונקציית תוסף Kotlin בשם getOrAwaitValue
שמוסיפה צופה, מקבלת את הערך LiveData
ולאחר מכן מנקה את הצופה – בעיקרון גרסה מקוצרת של קוד observeForever
שמוצגת למעלה. להסבר מלא על הכיתה, מומלץ לקרוא את הפוסט הזה בבלוג.
שלב 3. שימוש ב-getOrAPENDINGValue כדי לכתוב את הקביעה
בשלב זה, אתם משתמשים בשיטה getOrAwaitValue
וכותבים הצהרה שמצהירה שהnewTaskEvent
הופעל.
- קבלת הערך
LiveData
עבורnewTaskEvent
באמצעותgetOrAwaitValue
.
val value = tasksViewModel.newTaskEvent.getOrAwaitValue()
- הצהרת ערך שאינו Null.
assertThat(value.getContentIfNotHandled(), (not(nullValue())))
הבדיקה המלאה צריכה להיראות כמו הקוד הבא.
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.example.android.architecture.blueprints.todoapp.getOrAwaitValue
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.not
import org.hamcrest.Matchers.nullValue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
@Test
fun addNewTask_setsNewTaskEvent() {
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
// When adding a new task
tasksViewModel.addNewTask()
// Then the new task event is triggered
val value = tasksViewModel.newTaskEvent.getOrAwaitValue()
assertThat(value.getContentIfNotHandled(), not(nullValue()))
}
}
- מפעילים את הקוד וצופים בכרטיס הבדיקה!
עכשיו, אחרי שראיתם איך לכתוב בדיקה, תוכלו לכתוב בדיקה בעצמכם. בשלב הזה, השתמש במיומנויות שלמדת במהלך תרגול נוסף של ניסיון TasksViewModel
.
שלב 1. כתיבת בדיקה משלך ל-ViewModel
כותבים setFilterAllTasks_tasksAddViewVisible()
. בבדיקה הזאת צריך לוודא שאם סוג המסנן שלכם מוגדר להצגת כל המשימות, שלחצן הוספת משימה גלוי.
- לצורך שימוש ב-
addNewTask_setsNewTaskEvent()
לעיון, יש לכתוב בדיקה ב-TasksViewModelTest
שנקראתsetFilterAllTasks_tasksAddViewVisible()
שמגדירה את מצב הסינון ל-ALL_TASKS
, ומצהירה שה-DataDatatasksAddViewVisible
הואtrue
.
כדי להתחיל, צריך להשתמש בקוד שלמטה.
TasksViewModelTest
@Test
fun setFilterAllTasks_tasksAddViewVisible() {
// Given a fresh ViewModel
// When the filter type is ALL_TASKS
// Then the "Add task" action is visible
}
הערה:
- מספר ה-
TasksFilterType
של כל המשימות הואALL_TASKS.
- הרשאות הגישה של הלחצן להוספת משימה נשלטות על ידי
LiveData
tasksAddViewVisible.
- מריצים את הבדיקה.
שלב 2. השוואת הבדיקה לפתרון הבעיה
משווים את הפתרון שלכם לפתרון שלמטה.
TasksViewModelTest
@Test
fun setFilterAllTasks_tasksAddViewVisible() {
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
// When the filter type is ALL_TASKS
tasksViewModel.setFiltering(TasksFilterType.ALL_TASKS)
// Then the "Add task" action is visible
assertThat(tasksViewModel.tasksAddViewVisible.getOrAwaitValue(), `is`(true))
}
בודקים אם:
- יצרת את
tasksViewModel
עם אותה הצהרתApplicationProvider.getApplicationContext()
X ב-AndroidX. - בחרת להתקשר לשיטה
setFiltering
ולעבור את הערך בעמודהALL_TASKS
של סוג המסנן. - עליך לבדוק שה-
tasksAddViewVisible
נכון, באמצעות השיטהgetOrAwaitNextValue
.
שלב 3. הוספה של כלל @לפני
שימו לב איך בתחילת שתי הבדיקות אתם מגדירים TasksViewModel
.
TasksViewModelTest
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
אם יש לכם קודי הגדרה חוזרים עבור מספר בדיקות, תוכלו להשתמש בהערה @לפני כדי ליצור שיטת הגדרה ולהסיר קוד חוזר. מאחר שכל הבדיקות האלה אמורות לבדוק את TasksViewModel
, ונדרש מודל תצוגה מפורטת, יש להעביר את הקוד הזה לבלוק של @Before
.
- יוצרים משתנה למכונה בשם
lateinit
שנקראtasksViewModel|
. - יצירת שיטה שנקראת
setupViewModel
. - סימון הערות עם
@Before
. - העברת קוד אובייקט של מודל התצוגה ל-
setupViewModel
.
TasksViewModelTest
// Subject under test
private lateinit var tasksViewModel: TasksViewModel
@Before
fun setupViewModel() {
tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
}
- רוצה להריץ את הקוד?
אזהרה
אין לבצע את הפעולות הבאות, אין להפעיל את
tasksViewModel
עם ההגדרה של:
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
פעולה זו תגרום לשימוש באותו מופע לכל הבדיקות. יש להימנע מפעולה זו מפני שכל בדיקה צריכה להציג מופע חדש של הנושא בבדיקה (ה-ViewModel במקרה זה).
הקוד הסופי של TasksViewModelTest
אמור להיראות כמו הקוד הבא.
TasksViewModelTest
@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {
// Subject under test
private lateinit var tasksViewModel: TasksViewModel
// Executes each task synchronously using Architecture Components.
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
@Before
fun setupViewModel() {
tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
}
@Test
fun addNewTask_setsNewTaskEvent() {
// When adding a new task
tasksViewModel.addNewTask()
// Then the new task event is triggered
val value = tasksViewModel.newTaskEvent.awaitNextValue()
assertThat(
value?.getContentIfNotHandled(), (not(nullValue()))
)
}
@Test
fun getTasksAddViewVisible() {
// When the filter type is ALL_TASKS
tasksViewModel.setFiltering(TasksFilterType.ALL_TASKS)
// Then the "Add task" action is visible
assertThat(tasksViewModel.tasksAddViewVisible.awaitNextValue(), `is`(true))
}
}
אפשר ללחוץ כאן כדי לראות הבדל בין הקוד שהתחלת לבין הקוד הסופי.
כדי להוריד את הקוד עבור מעבדת הקוד הסופית, ניתן להשתמש בפקודת Git:
$ git clone https://github.com/googlecodelabs/android-testing.git $ cd android-testing $ git checkout end_codelab_1
לחלופין, אפשר להוריד את המאגר כקובץ ZIP, לפתוח אותו ב-Android Studio ולפתוח אותו.
מעבדת הקוד הזו כללה:
- איך להריץ בדיקות מ-Android Studio.
- ההבדל בין בדיקות מקומיות (
test
) לבין בדיקות אינסטרומנטציה (androidTest
). - איך לכתוב בדיקות של יחידה מקומית באמצעות JUNIT ו-Hamcrest.
- הגדרת בדיקות של ViewModel באמצעות ספריית הבדיקה של AndroidX.
קורס אוניברסיטה:
התיעוד של מפתח Android:
- מדריך לארכיטקטורת אפליקציות
- JUNIT4
- המארקסט
- ספריית הבדיקות של Robolectric
- ספריית הבדיקה של AndroidX
- ספריית הליבה של רכיבי הארכיטקטורה של AndroidX
- קבוצות מקור
- בדיקה משורת הפקודה
סרטי וידאו:
אחר:
קישורים למעבדות אחרות של הקוד בקורס הזה זמינים בדף הנחיתה של מכשירי Android מתקדמים בדף Kotlin codelabs.