অটোমেটেড ব্যাক-আপ ও রিস্টোর টেস্টিং

ব্যবহারকারী নতুন ডিভাইস সেট-আপ করলে বা আপনার অ্যাপ আবার ইনস্টল করলে, Android ক্লাউড ব্যাক-আপ বা ডিভাইস-টু-ডিভাইস ট্রান্সফার থেকে আপনার অ্যাপের ডেটা ফিরিয়ে আনতে পারে। আপনার ব্যাক-আপ সংক্রান্ত নিয়মে গুরুত্বপূর্ণ ডেটা বাদ দেওয়া হলে অথবা আপনার অ্যাপ রিস্টোর করা ডেটা ব্যবহার করতে না পারলে, ব্যবহারকারীরা কোনও সমস্যা দেখতে না পেয়েই তাদের সেটিংস ও প্রোগ্রেস হারিয়ে ফেলেন।

অটোমেটিক ব্যাক-আপ ও রিস্টোর টেস্ট আপনাকে অ্যাপ রিলিজ করার আগে এইসব সমস্যা ধরতে সাহায্য করে। এগুলি JUnit 5 টেস্ট যা আপনার ডেভেলপমেন্ট মেশিনে রান করে এবং Android ডিবাগ ব্রিজের (adb) মাধ্যমে কানেক্ট করা ডিভাইস কন্ট্রোল করে। প্রতিটি টেস্ট ডিভাইসে অ্যাপ ডেটা সিড করে, Android ব্যাক-আপ ফ্রেমওয়ার্কের মাধ্যমে অ্যাপ ব্যাক-আপ ও রিস্টোর করে এবং তারপরে ডেটা অক্ষত আছে কিনা তা চেক করে। আপনি নিজের মডিউলের বিল্ড ফাইলে Android Gradle প্লাগ-ইন (AGP) টেস্ট স্যুট হিসেবে টেস্ট কনফিগার করেন।

এটি কীভাবে কাজ করে

ব্যাক-আপ ও ফিরিয়ে আনার টেস্ট সুইটের দুটি অংশ আছে যা একসাথে কাজ করে:

  • হোস্ট টেস্ট হল JUnit 5 টেস্ট যা আপনার ডেভেলপমেন্ট মেশিনে রান করে। তারা ডেটা সিড করার জন্য প্রতিটি ডিভাইসের জন্য BackupRestoreController ব্যবহার করে, আপনার অ্যাপের ব্যাক-আপ নেয় ও ফিরিয়ে আনে এবং ফলাফল চেক করে।
  • ডিভাইস অ্যাকশন হল এমন ক্লাস যা BackupDeviceAction প্রয়োগ করে। এগুলি ডিভাইসে আপনার অ্যাপের প্রসেসে রান করে, তাই আপনার অ্যাপের নিজস্ব কোডের মাধ্যমে ডেটা পড়তে ও লিখতে পারে। হোস্ট ক্লাসের নাম দিয়ে কল ডিভাইস অ্যাকশন পরীক্ষা করে।

আপনি স্যুট চালালে, AGP আপনার অ্যাপ এবং একটি টেস্ট APK তৈরি করে যাতে আপনার ডিভাইস অ্যাকশন থাকে। প্রতিটি পরীক্ষার আগে, পরীক্ষার ফ্রেমওয়ার্ক, পরীক্ষা ব্যবহার করে এমন প্রতিটি ডিভাইসে দুটি APK ইনস্টল করে এবং তারপর আপনার অ্যাপের ডেটা মুছে দেয়।

বিল্ট-ইন স্টোরেজের ধরন

নিচের সারণীতে StorageDomain সাবক্লাসগুলি তালিকাভুক্ত করা আছে যেগুলি আপনাকে ডিভাইস অ্যাকশন না লিখে ডেটা সিড ও যাচাই করতে দেয়:

স্টোরেজ ডোমেন ডেটা
StorageDomain.Preference SharedPreferences ফাইলে একটি কী।
StorageDomain.Database SQLite ডেটাবেস টেবিলের একটি সারি।
StorageDomain.TextFile আপনার অ্যাপের ইন্টার্নাল স্টোরেজে থাকা একটি টেক্সট ফাইল।
StorageDomain.BinaryFile আপনার অ্যাপের ইন্টার্নাল স্টোরেজে একটি বাইনারি ফাইল।

DataStore ফাইলের মতো অন্যান্য ডেটা পরীক্ষা করতে, write device actions লিখুন।

পরিবহন মোড

প্রতিটি ব্যাক-আপে BackupTransportMode ভ্যালু ব্যবহার করা হয়। নিম্নলিখিত সারণীতে কাজ করে এমন পরিবহন মোডের তালিকা দেওয়া হল:

মোড পরিস্থিতি
LOCAL ডিভাইসের লোকাল ব্যাক-আপ ট্রান্সপোর্টে ব্যাক-আপ। ব্যাক-আপ ডেটা ডিভাইসে থেকে যায়।
CLOUD_ENCRYPTED ক্লাউড ব্যাক-আপ, যেমন ক্লায়েন্ট-সাইড এনক্রিপশন সহ ডিভাইস থেকে ব্যবহারকারীর Google অ্যাকাউন্টে সেভ করা ব্যাক-আপ।
CLOUD_UNENCRYPTED ক্লায়েন্ট-সাইড এনক্রিপশন নেই এমন ডিভাইস থেকে ক্লাউড ব্যাক-আপ।
DEVICE_TO_DEVICE একটি ডিভাইস থেকে অন্য ডিভাইসে ট্রান্সফার, যেমন কেবেল বা ওয়াই-ফাইয়ের মাধ্যমে।

LOCAL কাজ করে এমন যেকোনও ডিভাইসে কাজ করে। ক্লাউড এবং ডিভাইস-টু-ডিভাইস মোড Android Studio-তে অ্যাপ ডেটার ব্যাক-আপ নিন অ্যাকশনের মতো একই ব্যাক-আপ তৈরি করে: ব্যাক-আপ আপলোড বা অন্য ডিভাইসে পাঠানোর পরিবর্তে আপনার ডেভেলপমেন্ট মেশিনে সেভ করা হয়। ক্লাউড এবং ডিভাইস-টু-ডিভাইস মোডের জন্য ডিভাইসে Google Play পরিষেবা এবং আপনার অ্যাপের ডিবাগযোগ্য বিল্ড প্রয়োজন। আপনার ব্যাকআপ নিয়ম ক্লায়েন্ট-সাইড এনক্রিপশনের উপর নির্ভর করলে, উভয় ক্লাউড মোড পরীক্ষা করুন।

প্রয়োজনীয়তা

অটোমেটেড ব্যাক-আপ ও রিস্টোর টেস্টিং ব্যবহার করতে, আপনার এনভায়রনমেন্ট নিম্নলিখিত প্রয়োজনীয়তা পূরণ করছে কিনা তা নিশ্চিত করুন:

  • Gradle ভার্সন 9.6.0 বা তার পরবর্তী যেকোনও ভার্সন।
  • JDK ভার্সন ১৭ বা তার পরবর্তী যেকোনও ভার্সন।
  • Android 12 (API লেভেল 31) বা তার পরবর্তী যেকোনও ভার্সন চলছে এমন ডিভাইস বা এমুলেটর যা adb-এর মাধ্যমে কানেক্ট করা আছে। দুটি ডিভাইসের মধ্যে ট্রান্সফার পরীক্ষা করতে, দুটি ডিভাইস কানেক্ট করুন।

মানানসই

অটোমেটিক ব্যাক-আপ ও রিস্টোর টেস্টিংয়ের জন্য ন্যূনতম ও সাজেস্ট করা ভার্সন নিচের সারণীতে তালিকাভুক্ত করা হয়েছে:

কম্পোনেন্ট সর্বনিম্ন ভার্সন সাজেস্ট করা ভার্সন
Android Studio খরগোশ ২ ক্যানারি ১ Rabbit 2 Canary 4 বা তার পরের যেকোনও ভার্সন
Android Gradle প্লাগ-ইন (AGP) 9.5.0-alpha06 9.5.0-alpha09 বা তার পরবর্তী যেকোনও ভার্সন
androidx.test.backupটি লাইব্রেরি 1.0.0-alpha01 1.0.0-alpha02 বা তার পরের যেকোনও ভার্সন

AGP-এর প্রতিটি প্রিভিউ ভার্সনের জন্য Android Studio-এর ম্যাচিং প্রিভিউ ভার্সন প্রয়োজন। আরও তথ্যের জন্য, AGP প্রিভিউ দেখুন।

আপনার প্রোজেক্ট সেট-আপ করুন

আপনার অ্যাপ মডিউলে ব্যাক-আপ ও রিস্টোর টেস্ট স্যুট যোগ করতে, নিম্নলিখিত ধাপগুলি সম্পূর্ণ করুন:

এক্সপেরিমেন্টাল ফ্ল্যাগ চালু করুন

আপনার প্রোজেক্টের gradle.properties ফাইলে, টেস্ট স্যুট ও ব্যাক-আপ টেস্ট চালু করুন:

android.experimental.testSuiteSupport=true
android.experimental.enableBackupTest=true

টেস্ট স্যুট ঘোষণা করুন

আপনার অ্যাপ মডিউলের build.gradle.kts ফাইলে, testOptions ব্লকে ব্যাক-আপ টেস্ট স্যুট ঘোষণা করুন:

android {
    testOptions {
        backupTests {
            create("backupTest")
        }
    }
}

এই উদাহরণে, সুইটের নাম backupTest, সোর্স সেট ডিরেক্টরি এবং Gradle টাস্কের নাম নির্ধারণ করে। আপনি নিম্নলিখিত ঐচ্ছিক প্রপার্টি সহ স্যুট কাস্টমাইজ করতে পারবেন:

  • androidx.test.backup লাইব্রেরির ভার্সন সেট করতে backupTestLibraryVersion ব্যবহার করুন, যা AGP স্যুটে যোগ করে, যেমন "1.0.0-alpha02"। এই প্রপার্টি ঐচ্ছিক। আপনি এটি বাদ দিলে, AGP ভার্সনের উপর ভিত্তি করে AGP ডিফল্ট লাইব্রেরি ভার্সনে ফিরে আসে।
  • সুইট টেস্টের বিল্ড ভেরিয়েন্ট নির্দিষ্ট করতে targetVariants ব্যবহার করুন, যেমন targetVariants.add("demoDebug")। এই প্রপার্টি ঐচ্ছিক। আপনি এটি বাদ দিলে, সুইট আপনার মডিউলের testBuildType-এর ভেরিয়েন্ট টেস্ট করে, যা ডিফল্ট হিসেবে debug। আমরা ডিবাগ করা যায় এমন ভেরিয়েন্ট টেস্ট করার সাজেশন দিই কারণ ক্লাউড ও ডিভাইস-টু-ডিভাইস ট্রান্সপোর্ট মোডের জন্য ডিবাগ করা যায় এমন অ্যাপ প্রয়োজন।

AGP হোস্ট টেস্টে হোস্ট লাইব্রেরি, androidx.test.backup:backup-host এবং JUnit 5 যোগ করে। এটি টেস্ট APK-তে ডিভাইস লাইব্রেরি, androidx.test.backup:backup, যোগ করে এবং টেস্ট APK-এর ইনস্ট্রুমেন্টেশন রানার সেট করে।

অন্যান্য ডিপেন্ডেন্সি যোগ করতে, সুইটের hostJar এবং testApk ব্লক ব্যবহার করুন। যেমন, আপনার হোস্ট টেস্টে Truth ব্যবহার করতে, এটি hostJar ব্লকে যোগ করুন:

create("backupTest") {
    hostJar {
        dependencies {
            implementation("com.google.truth:truth:1.4.2")
        }
    }
}

সোর্স সেট তৈরি করা

সোর্স সেট ডিরেক্টরি তৈরি করুন যা স্যুট নামের সাথে মেলে:

  • src/{suiteName}/test/kotlin/-এ হোস্ট টেস্ট রাখুন।
  • src/{suiteName}/androidTest/kotlin/-এ ডিভাইস অ্যাকশন রাখুন।

যেমন, backupTest নামের একটি স্যুটে নিম্নলিখিত ডিরেক্টরি স্ট্রাকচার ব্যবহার করা হয়:

app/src/backupTest/
├── androidTest/
│   └── kotlin/com/example/myapp/ThemeActions.kt
└── test/
    └── kotlin/com/example/myapp/SettingsBackupTest.kt

আপনার ব্যাক-আপ কনফিগারেশন চেক করুন

আপনার অ্যাপের ব্যাক-আপ কনফিগারেশনে অন্তর্ভুক্ত ডেটা ব্যাক-আপ নেওয়া ও ফিরিয়ে আনার পরীক্ষা করে। আপনার অ্যাপের জন্য ব্যাক-আপ চালু আছে কিনা এবং আপনার ব্যাক-আপ নিয়মে আপনার টেস্ট করা ডেটা অন্তর্ভুক্ত আছে কিনা তা নিশ্চিত করুন।

ব্যাক-আপ ও ফিরিয়ে আনা সংক্রান্ত টেস্ট লেখা

সুইটের test সোর্স সেটে হোস্ট টেস্ট লিখুন। প্রতিটি টেস্ট ক্লাসে দুটি অ্যানোটেশন থাকতে হবে:

  • @ExtendWith(BackupRestoreExtension::class) পরীক্ষা করার জন্য কানেক্ট করা ডিভাইস প্রদান করে।
  • @BackupRestoreConfig(applicationId = "...") টেস্ট করা হচ্ছে এমন অ্যাপের অ্যাপ্লিকেশন আইডি সেট করে। আপনি যে ভ্যারিয়েন্ট পরীক্ষা করছেন তার অ্যাপ্লিকেশন আইডি ব্যবহার করুন, এর মধ্যে যেকোনও applicationIdSuffix অন্তর্ভুক্ত।

প্রতিটি টেস্ট মেথড, প্রতিটি ডিভাইসের জন্য একটি BackupRestoreController প্যারামিটার ঘোষণা করে যা এটি ব্যবহার করে।

বিল্ট-ইন স্টোরেজের ধরন টেস্ট করুন

বিল্ট-ইন স্টোরেজ টাইপ পরীক্ষা করতে, সিড করার ডেটা, ব্যাক-আপ ফাইলের জন্য ডিরেক্টরি এবং ট্রান্সপোর্ট মোড সহ runBackupRestoreFlow কল করুন। The পদ্ধতি ডিভাইসে নিম্নলিখিত ধাপগুলি রান করে:

  1. প্রতিটি স্টোরেজ ডোমেনে সিড।
  2. অ্যাপ বন্ধ করে।
  3. অ্যাপের ব্যাক-আপ নেয়।
  4. অ্যাপের ডেটা মুছে দেয়।
  5. ব্যাক-আপ ফিরিয়ে আনে।
  6. প্রতিটি স্টোরেজ ডোমেনে সিড ভ্যালু আছে কিনা তা যাচাই করে।

কোনও ধাপ সম্পূর্ণ না হলে, পদ্ধতিটি একটি ব্যতিক্রম তৈরি করে, যার ফলে পরীক্ষাটি সম্পূর্ণ হয় না। নিম্নলিখিত উদাহরণটি স্থানীয় ব্যাক-আপ ট্রান্সপোর্ট ব্যবহার করে একটি SharedPreferences কী, একটি SQLite সারি এবং একটি ইন্টার্নাল ফাইল পরীক্ষা করে:

package com.example.myapp

import androidx.test.backup.host.BackupRestoreConfig
import androidx.test.backup.host.BackupRestoreController
import androidx.test.backup.host.BackupRestoreExtension
import androidx.test.backup.host.BackupTransportMode
import androidx.test.backup.host.StorageDomain
import java.nio.file.Path
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.io.TempDir

@ExtendWith(BackupRestoreExtension::class)
@BackupRestoreConfig(applicationId = "com.example.myapp")
class SettingsBackupTest {

    @Test
    fun settingsSurviveBackupAndRestore(
        device: BackupRestoreController,
        @TempDir outputDir: Path,
    ): Unit = runBlocking {
        device.runBackupRestoreFlow(
            storages = listOf(
                StorageDomain.Preference(
                    prefName = "settings",
                    key = "theme",
                    value = "dark",
                ),
                StorageDomain.Database(
                    dbName = "notes.db",
                    table = "notes",
                    primaryKeyCol = "id",
                    primaryKeyVal = 1,
                    columnValues = mapOf("title" to "Groceries"),
                ),
                StorageDomain.TextFile(
                    path = "drafts/note.txt",
                    content = "Buy milk",
                ),
            ),
            outputDir = outputDir,
            mode = BackupTransportMode.LOCAL,
        )
    }
}

স্টোরেজ ডোমেন নির্ধারণ করার সময় নিম্নলিখিত বিষয়গুলি মনে রাখবেন:

  • Preference, SharedPreferences ফাইলের নাম নেয়, তবে .xml এক্সটেনশন ছাড়াই।
  • TextFile এবং BinaryFile আপনার অ্যাপের filesDir-এর সাথে আপেক্ষিক পাথ সমাধান করে।
  • Database SQL-এর মাধ্যমে সারি লেখে এবং টেবিল না থাকলে TEXT কলাম সহ টেবিল তৈরি করে। আপনার অ্যাপ Room ব্যবহার করলে, আমরা সাজেস্ট করি যে ডিভাইস অ্যাকশন-এর মাধ্যমে ডেটাবেস কন্টেন্ট পরীক্ষা করুন যা আপনার DAO ব্যবহার করে যাতে ডেটাবেসে Room-এর প্রত্যাশিত স্কিমা থাকে।

ডিভাইস অ্যাকশন লেখা

বিল্ট-ইন স্টোরেজের ধরন কভার করে না এমন ডেটা সিড বা যাচাই করতে, সুইটের androidTest সোর্স সেটে ডিভাইস অ্যাকশন লিখুন। একটি ডিভাইস অ্যাকশন BackupDeviceAction প্রয়োগ করে এবং দুটি মেম্বারকে ওভাররাইড করে:

  • ডেটা সিড করে এমন অ্যাকশনের জন্য phase-কে BackupDeviceAction.PHASE_POPULATE-এ সেট করুন অথবা ডেটা চেক করে এমন অ্যাকশনের জন্য BackupDeviceAction.PHASE_VERIFY-এ সেট করুন।
  • আপনার অ্যাপের Context এবং হোস্ট টেস্ট থেকে পাওয়া আর্গুমেন্ট সহ অ্যাকশন চালানোর জন্য execute প্রয়োগ করুন। BackupDeviceActionResult.success বা BackupDeviceActionResult.failure ফ্যাক্টরি পদ্ধতির মাধ্যমে তৈরি করা ফলাফল রিটার্ন করুন এবং failure-এ একটি ত্রুটি মেসেজ পাস করুন।

execute পদ্ধতিটি আপনার অ্যাপের প্রসেসে ব্যাকগ্রাউন্ড থ্রেডে চলে, তাই এটি রিড ও রাইট শেষ না হওয়া পর্যন্ত ব্লক করতে পারে।

নিম্নলিখিত উদাহরণটি Preferences DataStore-এর মাধ্যমে অ্যাপ স্টোর করে এমন একটি থিম সেটিং সিড ও যাচাই করে। অ্যাপটি তার প্রধান সোর্স সেটে DataStore সংজ্ঞায়িত করে:

// In app/src/main/kotlin/com/example/myapp/Settings.kt
package com.example.myapp

import android.content.Context
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore

val Context.settingsDataStore by preferencesDataStore(name = "settings")
val THEME_KEY = stringPreferencesKey("theme")

ডিভাইস অ্যাকশন একই সংজ্ঞা ব্যবহার করে:

// In app/src/backupTest/androidTest/kotlin/com/example/myapp/ThemeActions.kt
package com.example.myapp

import android.content.Context
import androidx.datastore.preferences.core.edit
import androidx.test.backup.BackupDeviceAction
import androidx.test.backup.BackupDeviceActionArgs
import androidx.test.backup.BackupDeviceActionResult
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking

class SeedThemeAction : BackupDeviceAction {
    override val phase = BackupDeviceAction.PHASE_POPULATE

    override fun execute(
        context: Context,
        args: BackupDeviceActionArgs,
    ): BackupDeviceActionResult {
        val theme = args["theme"]
            ?: return BackupDeviceActionResult.failure("Missing theme argument")
        runBlocking {
            context.settingsDataStore.edit { it[THEME_KEY] = theme }
        }
        return BackupDeviceActionResult.success()
    }
}

class VerifyThemeAction : BackupDeviceAction {
    override val phase = BackupDeviceAction.PHASE_VERIFY

    override fun execute(
        context: Context,
        args: BackupDeviceActionArgs,
    ): BackupDeviceActionResult {
        val expected = args["theme"]
        val actual = runBlocking {
            context.settingsDataStore.data.first()[THEME_KEY]
        }
        return if (actual == expected) {
            BackupDeviceActionResult.success()
        } else {
            BackupDeviceActionResult.failure("Expected $expected, found $actual")
        }
    }
}

হোস্ট টেস্টে ডেটা ফেরত পাঠাতে, success পদ্ধতিতে একটি ম্যাপ পাস করুন। হোস্ট টেস্ট BackupActionResult.Success.data থেকে ম্যাপ পড়ে।

ফ্লোয়ের প্রতিটি ধাপ রান করুন

ডিভাইস অ্যাকশন ব্যবহার করতে বা ফ্লো কাস্টমাইজ করতে, প্রতিটি ধাপ নিজে কল করুন। নিম্নলিখিত হোস্ট টেস্ট, ক্লাউড ব্যাক-আপ ও রিস্টোর সংক্রান্ত পূর্ববর্তী বিভাগ থেকে ডিভাইস অ্যাকশন রান করে:

package com.example.myapp

import androidx.test.backup.host.BackupActionResult
import androidx.test.backup.host.BackupRestoreConfig
import androidx.test.backup.host.BackupRestoreController
import androidx.test.backup.host.BackupRestoreExtension
import androidx.test.backup.host.BackupTransportMode
import java.nio.file.Path
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.fail
import org.junit.jupiter.api.io.TempDir

const val SEED_THEME = "com.example.myapp.SeedThemeAction"
const val VERIFY_THEME = "com.example.myapp.VerifyThemeAction"

@ExtendWith(BackupRestoreExtension::class)
@BackupRestoreConfig(applicationId = "com.example.myapp")
class ThemeBackupTest {

    @Test
    fun themeSurvivesCloudBackup(
        device: BackupRestoreController,
        @TempDir outputDir: Path,
    ): Unit = runBlocking {
        val args = mapOf("theme" to "dark")
        device.runOnDevice(SEED_THEME, args).assertSuccess()

        device.stopApp()
        val backupFile = device.performBackup(
            BackupTransportMode.CLOUD_ENCRYPTED,
            outputDir,
        )
        device.clearAppData()
        device.performRestore(backupFile)

        device.runOnDevice(VERIFY_THEME, args).assertSuccess()
    }
}

fun BackupActionResult.assertSuccess() {
    if (this is BackupActionResult.Failure) fail(errorMessage)
}

কোনও ডিভাইস অ্যাকশন ব্যর্থ হলে, runOnDevice ব্যতিক্রম দেখানোর পরিবর্তে BackupActionResult.Failure রিটার্ন করে, তাই ফলাফল চেক করুন। অন্যান্য ধাপগুলি ব্যর্থ হলে একটি ব্যতিক্রম থ্রো করে।

ডিভাইসের মধ্যে ট্রান্সফার পরীক্ষা করা

দুটি ডিভাইসের মধ্যে ট্রান্সফার পরীক্ষা করতে, প্রতিটি ডিভাইসের জন্য একটি BackupRestoreController প্যারামিটার ঘোষণা করুন। সোর্স ডিভাইসে অ্যাপের ব্যাক-আপ নিন এবং তারপরে টার্গেট ডিভাইসে ব্যাক-আপ ফাইল রিস্টোর করুন। নিম্নলিখিত উদাহরণটি আগের উদাহরণ থেকে কনস্ট্যান্ট এবং assertSuccess হেল্পার আবার ব্যবহার করে:

package com.example.myapp

import androidx.test.backup.host.BackupRestoreConfig
import androidx.test.backup.host.BackupRestoreController
import androidx.test.backup.host.BackupRestoreExtension
import androidx.test.backup.host.BackupTransportMode
import androidx.test.backup.host.Device
import java.nio.file.Path
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.io.TempDir

@ExtendWith(BackupRestoreExtension::class)
@BackupRestoreConfig(applicationId = "com.example.myapp")
class ThemeTransferTest {

    @Test
    fun themeTransfersToNewDevice(
        @Device(role = "source") source: BackupRestoreController,
        @Device(role = "target") target: BackupRestoreController,
        @TempDir outputDir: Path,
    ): Unit = runBlocking {
        val args = mapOf("theme" to "dark")
        source.runOnDevice(SEED_THEME, args).assertSuccess()
        source.stopApp()
        val backupFile = source.performBackup(
            BackupTransportMode.DEVICE_TO_DEVICE,
            outputDir,
        )

        target.clearAppData()
        target.performRestore(backupFile)
        target.runOnDevice(VERIFY_THEME, args).assertSuccess()
    }
}

@Device-এর role ভ্যালু হল একটি লেবেল যা টেস্টটি পড়া সহজ করে তোলে। কোনও প্যারামিটার কোন ডিভাইসে যাবে তা এর দ্বারা প্রভাবিত হয় না। শুধুমাত্র একটি ডিভাইস কানেক্ট করা থাকলে, দুটি প্যারামিটারই সেই ডিভাইস ব্যবহার করে এবং পরীক্ষাটি একটি ডিভাইসে ট্রান্সফার করার প্রসেসকে সিমুলেট করে। টার্গেটের ডেটা মুছে দিলে, রিস্টোর করা ডেটা যে ব্যাক-আপ থেকে এসেছে তা নিশ্চিত করা যায়।

ডিভাইস বেছে নিন

ডিফল্ট হিসেবে, টেস্ট ফ্রেমওয়ার্ক অনলাইন ডিভাইসগুলিকে সিরিয়াল নম্বর অনুযায়ী সাজায় এবং অবস্থান অনুযায়ী সেগুলিকে BackupRestoreController প্যারামিটারে অ্যাসাইন করে। যেমন, টেস্ট মেথডের প্রথম প্যারামিটার প্রথম ডিভাইস পায় এবং দ্বিতীয় প্যারামিটার দ্বিতীয় ডিভাইস পায়। কোনও পজিশনের জন্য কোনও ডিভাইস না থাকলে, প্যারামিটার প্রথম ডিভাইসটি পায়। পজিশন পদ্ধতিতে সব প্যারামিটার গণনা করা হয়, তাই অন্যান্য প্যারামিটারের আগে ডিভাইস প্যারামিটার ঘোষণা করুন, যেমন @TempDir। ANDROID_SERIAL এনভায়রনমেন্ট ভেরিয়েবল ডিভাইস অ্যাসাইনমেন্টকে প্রভাবিত করে না।

ডিভাইস বেছে নিতে, serial বা api-এর @Device ভ্যালু সেট করুন অথবা JVM সিস্টেম প্রপার্টি সেট করুন। সিস্টেম প্রপার্টি @Device ভ্যালুর চেয়ে বেশি অগ্রাধিকার পায়। নিম্নলিখিত সারণীতে কাজ করে এমন সিস্টেম প্রপার্টির তালিকা দেওয়া হল:

সিস্টেম প্রপার্টি বর্ণনা
androidx.test.backup.device.serial সব ডিভাইস প্যারামিটারের জন্য ডিভাইসের সিরিয়াল নম্বর।
androidx.test.backup.device.serials ক্রমিক সংখ্যার কমা-বিভাজিত তালিকা, যা পজিশন অনুযায়ী প্যারামিটারে অ্যাসাইন করা হয়েছে।
androidx.test.backup.device.serial.{name} @Device(serial = "{name}") দিয়ে অ্যানোটেট করা প্যারামিটারের সিরিয়াল নম্বর।
androidx.test.backup.device.api সব ডিভাইস প্যারামিটারের জন্য ডিভাইসের API লেভেল।
androidx.test.backup.device.apis API লেভেলের কমা দিয়ে আলাদা করা তালিকা, যা পজিশন অনুযায়ী প্যারামিটারে অ্যাসাইন করা হয়েছে।

কমান্ড লাইন থেকে পরীক্ষা চালানোর সময় -D-এর মাধ্যমে এইসব প্রপার্টি পাস করুন। প্রপার্টিগুলি প্রতিটি টেস্টের ক্ষেত্রে প্রযোজ্য, তাই শুধুমাত্র সেই টেস্টগুলি চালানোর জন্য --tests বিকল্পটি ব্যবহার করুন যেগুলির জন্য সেগুলি প্রয়োজন। যেমন, নিচে উল্লেখ করা কমান্ডটি ThemeTransferTest-কে সোর্স ডিভাইস emulator-5554 এবং emulator-5556-কে টার্গেট ডিভাইস হিসেবে রান করে:

./gradlew :app:testDebugBackupTestDefaultTestSuite --tests "com.example.myapp.ThemeTransferTest" -Dandroidx.test.backup.device.serials=emulator-5554,emulator-5556

টেস্টের মধ্যে অ্যাপ ডেটা রাখুন

প্রতিটি পরীক্ষার আগে, টেস্ট ফ্রেমওয়ার্ক প্রতিটি ডিভাইসে আপনার অ্যাপের ডেটা মুছে দেয় যা পরীক্ষা ব্যবহার করে। পরীক্ষা ক্লাস বা পদ্ধতির জন্য এটি বন্ধ করতে, এটিকে @Isolation(IsolationPolicy.MANUAL) দিয়ে অ্যানোটেট করুন।

জাভাতে টেস্ট লিখুন

BackupRestoreController মেথড হল Kotlin সাসপেন্ড ফাংশন। আপনি Java-তে হোস্ট টেস্ট লিখলে, Async প্রতিটি পদ্ধতির ভ্যারিয়েন্ট ব্যবহার করুন, যেমন runBackupRestoreFlowAsync, যা ListenableFuture রিটার্ন করে।

ব্যাক-আপ ও ফিরিয়ে আনার টেস্ট রান করা

স্যুট টেস্ট করে এমন প্রতিটি ভ্যারিয়েন্টের জন্য AGP একটি করে Gradle টাস্ক তৈরি করে, যার নাম test{Variant}{SuiteName}DefaultTestSuite। debug ভ্যারিয়েন্টের বিরুদ্ধে backupTest স্যুট চালাতে, আপনার ডিভাইস কানেক্ট করুন এবং টাস্কটি চালান:

./gradlew :app:testDebugBackupTestDefaultTestSuite

check, test ও connectedCheck টাস্ক ব্যাক-আপ ও রিস্টোর টেস্ট স্যুট রান করে না, তাই স্যুট টাস্ক স্পষ্টভাবে রান করুন।

একটি টেস্ট ক্লাস বা পদ্ধতি রান করতে, --tests বিকল্প ব্যবহার করুন:

./gradlew :app:testDebugBackupTestDefaultTestSuite --tests "com.example.myapp.ThemeBackupTest"

পরীক্ষার রিপোর্ট চেক করা

টেস্ট রান সম্পূর্ণ হওয়ার পরে, AGP {module}/build/reports/tests/{taskName}/index.html-এ HTML টেস্ট রিপোর্ট তৈরি করে, যেমন app/build/reports/tests/testDebugBackupTestDefaultTestSuite/index.html।

পরিচিত সমস্যা ও সীমাবদ্ধতা

অটোমেটেড ব্যাক-আপ ও রিস্টোর টেস্টিংয়ের ক্ষেত্রে নিম্নলিখিত পরিচিত সমস্যা ও সীমাবদ্ধতা রয়েছে:

  • টেস্ট স্যুটের জন্য Android Studio সহায়তা এখনও উপলভ্য নয়। আপনার প্রোজেক্ট সঠিকভাবে কনফিগার করা থাকলেও, কোড এডিটর টেস্ট স্যুট সোর্স ফাইলে সমাধান না হওয়া রেফারেন্স সংক্রান্ত সমস্যা দেখাতে পারে। এর পরিবর্তে Gradle ব্যবহার করে কমান্ড লাইন থেকে ব্যাক-আপ ও রিস্টোর টেস্ট তৈরি ও রান করুন।
  • শুধু সেইসব ডিভাইস ও এমুলেটরেই পরীক্ষা চালানো হয় যেগুলি adb-এর মাধ্যমে আপনার ডেভেলপমেন্ট মেশিনের সাথে কানেক্ট করা আছে। Firebase Test Lab কাজ করে না।
  • টেস্ট আপনার অ্যাপের ডেটা মুছে দেয় এবং যে ডিভাইসে টেস্ট করা হয় সেটির ব্যাক-আপ সেটিংস পরিবর্তন করে। আমরা সাজেস্ট করি যে, এর জন্য আলাদা টেস্ট ডিভাইস ব্যবহার করুন।

প্রতিটি রিলিজে হওয়া পরিবর্তনের জন্য, ব্যাক-আপ ও রিস্টোর টেস্টিং রিলিজ নোট দেখুন।