App Actions টেস্ট লাইব্রেরি

অ্যাপ অ্যাকশন টেস্ট লাইব্রেরি (AATL) ডেভেলপারদের প্রোগ্রাম্যাটিকভাবে অ্যাপ অ্যাকশন ফুলফিলমেন্ট পরীক্ষা করার ক্ষমতা প্রদান করে, যা সাধারণত প্রকৃত ভয়েস কোয়েরি বা অ্যাপ অ্যাকশন টেস্ট টুল ব্যবহার করে করা হয়।

লাইব্রেরিটি নিশ্চিত করতে সাহায্য করে যে shortcut.xml কনফিগারেশন সঠিক এবং বর্ণিত Android ইনটেন্ট ইনভোকেশন সফল হয়েছে। অ্যাপ অ্যাকশন টেস্ট লাইব্রেরি আপনার অ্যাপের নির্দিষ্ট Google Assistant ইনটেন্ট ও প্যারামিটার পূরণ করার ক্ষমতা পরীক্ষা করার জন্য একটি মেকানিজম প্রদান করে। এটি করার জন্য, এটি সেগুলিকে একটি Android ডিপ লিঙ্ক বা Android ইনটেন্টে রূপান্তর করে, যা একটি Android অ্যাক্টিভিটি ইনস্ট্যান্টিয়েট করতে ব্যবহার করা যেতে পারে।

Android এনভায়রনমেন্টে Robolectric ইউনিট বা ইনস্ট্রুমেন্টেড টেস্টের মাধ্যমে পরীক্ষা করা হয়। এটি ডেভেলপারদের তাদের অ্যাপ্লিকেশনটি আসল অ্যাপের মতো আচরণ করে ব্যাপকভাবে পরীক্ষা করার অনুমতি দেয়। BII, কাস্টম ইনটেন্ট বা ডিপ লিঙ্ক ফুলফিলমেন্ট পরীক্ষা করার জন্য, যেকোনও ইনস্ট্রুমেন্টেড টেস্টিং ফ্রেমওয়ার্ক ব্যবহার করা যেতে পারে (UI Automator, Espresso, JUnit4, Appium, Detox, Calabash)।

অ্যাপ্লিকেশনটি বহুভাষিক হলে, ডেভেলপাররা যাচাই করতে পারেন যে অ্যাপ্লিকেশনটির কার্যকারিতা বিভিন্ন লোকেলে সঠিকভাবে কাজ করছে কিনা।

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

অ্যাপের টেস্টিং এনভায়রনমেন্টের মধ্যে অ্যাপ অ্যাকশন টেস্ট লাইব্রেরি ইন্টিগ্রেট করতে, ডেভেলপারদের অ্যাপের app মডিউলে নতুন রোবোলেক্ট্রিক বা ইনস্ট্রুমেন্টেড টেস্ট তৈরি করতে বা আগে থেকে থাকা টেস্ট আপডেট করতে হবে।

টেস্ট কোডে নিম্নলিখিত অংশগুলি থাকে:

  • সাধারণ সেট-আপ পদ্ধতি বা স্বতন্ত্র টেস্ট কেসে লাইব্রেরি ইনস্ট্যান্সের ইনিশিয়ালাইজেশন।
  • ইনটেন্ট তৈরির ফলাফল পেতে প্রতিটি স্বতন্ত্র টেস্ট লাইব্রেরি ইনস্ট্যান্সের fulfill মেথডকে কল করে।
  • তারপর ডেভেলপার ডিপ লিঙ্ক অ্যাসার্ট করেন বা অ্যাপ ফুলফিলমেন্ট ট্রিগার করেন, এবং অ্যাপের স্ট্যাটাসে কাস্টম ভ্যালিডেশন চালান।

সেট-আপ করার জন্য প্রয়োজনীয় শর্ত

টেস্ট লাইব্রেরি ব্যবহার করার জন্য, আপনার অ্যাপ্লিকেশনে টেস্ট যোগ করার আগে কিছু প্রাথমিক অ্যাপ কনফিগারেশন প্রয়োজন।

কনফিগারেশন

অ্যাপ অ্যাকশন টেস্ট লাইব্রেরি ব্যবহার করতে, আপনার অ্যাপ নিম্নলিখিত উপায়ে কনফিগার করা আছে কিনা তা নিশ্চিত করুন:

  • Android Gradle প্লাগ-ইন (AGP) ইনস্টল করুন
  • app মডিউলের res/xml ফোল্ডারে shortcuts.xml ফাইল যোগ করুন।
  • নিশ্চিত করুন যে AndroidManifest.xml-এ <meta-data android:name="android.app.shortcuts" android:resource=”@xml/shortcuts” /> অন্তর্ভুক্ত আছে এগুলির মধ্যে যেকোনও একটির অধীনে:
    • <application> ট্যাগ
    • লঞ্চার <activity> ট্যাগ
  • shortcuts.xml-এ <shortcuts> এলিমেন্টের মধ্যে <capability> এলিমেন্ট রাখুন

অ্যাপ অ্যাকশন টেস্ট লাইব্রেরি ডিপেন্ডেন্সি যোগ করুন

  1. settings.gradle-এ প্রোজেক্ট রিপোজিটরির তালিকায় Google রিপোজিটরি যোগ করুন:

        allprojects {
            repositories {
                …
                google()
            }
        }
    
  2. অ্যাপ মডিউল build.gradle ফাইলে, AATL ডিপেন্ডেন্সি যোগ করুন:

        androidTestImplementation 'com.google.assistant.appactions:testing:1.0.0'
    

    আপনি যে লাইব্রেরি ডাউনলোড করেছেন সেটির ভার্সন নম্বর ব্যবহার করছেন কিনা তা নিশ্চিত করুন।

ইন্টিগ্রেশন টেস্ট তৈরি করুন

  1. app/src/androidTest-এর অধীনে নতুন পরীক্ষা তৈরি করুন। Robolectric পরীক্ষার জন্য, app/src/test-এর অধীনে সেগুলি তৈরি করুন:

    Kotlin

      
        import android.content.Context
        import android.content.Intent
        import android.widget.TextView
        import androidx.test.core.app.ApplicationProvider
        import androidx.test.core.app.ActivityScenario
        import com.google.assistant.appactions.testing.aatl.AppActionsTestManager
        import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentIntentResult
        import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentResult
        import com.google.assistant.appactions.testing.aatl.fulfillment.FulfillmentType
        import com.google.common.collect.ImmutableMap
        import org.junit.Assert.assertEquals
        import org.junit.Before
        import org.junit.runner.RunWith
        import org.junit.Test
        import org.robolectric.RobolectricTestRunner
        …
        @Test
        fun IntentTestExample() {
          val intentParams = mapOf("feature" to "settings")
          val intentName = "actions.intent.OPEN_APP_FEATURE"
          val result = aatl.fulfill(intentName, intentParams)
    
          assertEquals(FulfillmentType.INTENT, result.getFulfillmentType())
    
          val intentResult = result as AppActionsFulfillmentIntentResult
          val intent = intentResult.intent
    
          // Developer can choose to assert different relevant properties of the returned intent, such as the action, activity, package, scheme and so on
          assertEquals("youtube", intent.scheme)
          assertEquals("settings", intent.getStringExtra("featureParam"))
          assertEquals("actions.intent.OPEN_APP_FEATURE", intent.action)
          assertEquals("com.google.android.youtube/.MainActivity",
              intent.component.flattenToShortString())
          assertEquals("com.google.myapp", intent.package)
    
          // Developers can choose to use returned Android Intent to launch and assess the activity. Below are examples for how it will look like for Robolectric and Espresso tests.
          // Please note that the below part is just a possible example of how Android tests are validating Activity functionality correctness for given Android Intent.
    
          // Robolectric example:
          val activity = Robolectric.buildActivity(MainActivity::class.java,
            intentResult.intent).create().resume().get()
    
          val title: TextView = activity.findViewById(R.id.startActivityTitle)
          assertEquals(title?.text?.toString(), "Launching…")
        }
      

    জাভা

      
        import android.content.Context;
        import android.content.Intent;
        import android.widget.TextView;
        import androidx.test.core.app.ApplicationProvider;
        import androidx.test.core.app.ActivityScenario;
        import com.google.assistant.appactions.testing.aatl.AppActionsTestManager;
        import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentIntentResult;
        import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentResult;
        import com.google.assistant.appactions.testing.aatl.fulfillment.FulfillmentType;
        import com.google.common.collect.ImmutableMap;
        import org.junit.Assert.assertEquals;
        import org.junit.Before;
        import org.junit.runner.RunWith;
        import org.junit.Test;
        import org.robolectric.RobolectricTestRunner;
        ...
        @Test
          public void IntentTestExample() throws Exception {
            Map<String, String> intentParams = ImmutableMap.of("feature", "settings");
            String intentName = "actions.intent.OPEN_APP_FEATURE";
            AppActionsFulfillmentResult result = aatl.fulfill(intentName, intentParams);
    
            assertEquals(FulfillmentType.INTENT, result.getFulfillmentType());
    
            AppActionsFulfillmentIntentResult intentResult = (AppActionsFulfillmentIntentResult) result;
    
            Intent intent = intentResult.getIntent();
    
            // Developer can choose to assert different relevant properties of the returned intent, such as the action, activity, package, or scheme
            assertEquals("settings", intent.getStringExtra("featureParam"));
            assertEquals("actions.intent.OPEN_APP_FEATURE", intent.getAction());
            assertEquals("com.google.android.youtube/.MainActivity", intent.getComponent().flattenToShortString());
            assertEquals("com.google.myapp", intent.getPackage());
    
            // Developers can choose to use returned Android Intent to launch and assess the   activity. Below are examples for how it will look like for Robolectric and  Espresso tests.
            // Please note that the below part is just a possible example of how Android tests are validating Activity functionality correctness for given Android Intent.
    
            // Robolectric example:
            MainActivity activity = Robolectric.buildActivity(MainActivity.class,intentResult.intent).create().resume().get();
    
            TextView title: TextView = activity.findViewById(R.id.startActivityTitle)
            assertEquals(title?.getText()?.toString(), "Launching…")
          }
      

    আপনি Espresso ব্যবহার করলে, AATL ফলাফলের উপর ভিত্তি করে অ্যাক্টিভিটি কীভাবে লঞ্চ করবেন তা আপনাকে পরিবর্তন করতে হবে। ActivityScenario পদ্ধতি ব্যবহার করে Espresso-এর একটি উদাহরণ এখানে দেওয়া হল:

    Kotlin

        
        ActivityScenario.launch<MainActivity>(intentResult.intent);
        Espresso.onView(ViewMatchers.withId(R.id.startActivityTitle))
          .check(ViewAssertions.matches(ViewMatchers.withText("Launching…")))
        

    জাভা

        
          ActivityScenario.launch<MainActivity>(intentResult.intent);
          Espresso.onView(ViewMatchers.withId(R.id.startActivityTitle))
            .check(ViewAssertions.matches(ViewMatchers.withText("Launching…")))
        
  2. প্যারামিটার ম্যাপিংয়ে নাম ও মূল প্রপার্টি যেন BII-এর প্যারামিটারের সাথে ম্যাচ করে। যেমন, exercisePlan.forExercise.name, GET_EXERCISE_PLAN-এ প্যারামিটারের জন্য ডকুমেন্টেশনের সাথে মেলে।

  3. Android Context প্যারামিটার (ApplicationProvider বা InstrumentationRegistry থেকে প্রাপ্ত):

    • সিঙ্গেল মডিউল অ্যাপ আর্কিটেকচার:

    Kotlin

        
          private lateinit var aatl: AppActionsTestManager
          @Before
          fun init() {
            val appContext = ApplicationProvider.getApplicationContext()
            aatl = AppActionsTestManager(appContext)
          }
        
      

    জাভা

        
          private AppActionsTestManager aatl;
    
          @Before
          public void init() {
            Context appContext = ApplicationProvider.getApplicationContext();
            aatl = new AppActionsTestManager(appContext);
          }
        
      
    • মাল্টি-মডিউল অ্যাপ আর্কিটেকচার:

    Kotlin

        
          private lateinit var aatl: AppActionsTestManager
    
          @Before
          fun init() {
            val appContext = ApplicationProvider.getApplicationContext()
            val lookupPackages = listOf("com.myapp.mainapp", "com.myapp.resources")
            aatl = AppActionsTestManager(appContext, lookupPackages)
          }
        
      

    জাভা

        
          private AppActionsTestManager aatl;
    
          @Before
          public void init() throws Exception {
    
            Context appContext = ApplicationProvider.getApplicationContext();
            List<String> lookupPackages = Arrays.asList("com.myapp.mainapp","com.myapp.resources");
            aatl = new AppActionsTestManager(appContext, Optional.of(lookupPackages));
          }
        
      
  4. API-এর fulfill পদ্ধতিটি এক্সিকিউট করুন এবং AppActionsFulfillmentResult অবজেক্টটি পান।

অ্যাসার্শন পারফর্ম করুন

App Actions টেস্ট লাইব্রেরি অ্যাসার্ট করার জন্য সাজেস্ট করা পদ্ধতি হল:

  1. AppActionsFulfillmentResult-এর ফুলফিলমেন্টের ধরন অ্যাসার্ট করুন। অপ্রত্যাশিত BII অনুরোধের ক্ষেত্রে অ্যাপটি কীভাবে আচরণ করে তা পরীক্ষা করার জন্য এটি FulfillmentType.INTENT, বা FulfillmentType.UNFULFILLED হতে হবে।
  2. ফুলফিলমেন্টের ২ ধরনের ফ্লেভার আছে: INTENT এবং DEEPLINK ফুলফিলমেন্ট।
    • সাধারণত, ডেভেলপার INTENT এবং DEEPLINK-এর মধ্যে পার্থক্য করতে পারেন shortcuts.xml-এ ইনটেন্ট ট্যাগ দেখে যা তারা লাইব্রেরি ট্রিগার করে পূরণ করছেন।
    • ইন্টেন্ট ট্যাগের অধীনে url-template ট্যাগ থাকলে, এটি ইঙ্গিত করে যে DEEPLINK এই ইন্টেন্ট পূরণ করে।
    • ফলাফল ইনটেন্টের getData() পদ্ধতি যদি নন-নাল অবজেক্ট রিটার্ন করে, তাহলে এটিওDEEPLINK ফুলফিলমেন্ট নির্দেশ করে। একইভাবে, getData যদি null রিটার্ন করে, তাহলে বুঝতে হবে যে এটি INTENT ফুলফিলমেন্ট।
  3. INTENT কেসের জন্য, AppActionsFulfillmentResult-কে AppActionsIntentFulfillmentResult-এ টাইপকাস্ট করুন, getIntent পদ্ধতি কল করে Android ইনটেন্ট ফেচ করুন এবং নিম্নলিখিতগুলির মধ্যে একটি করুন:
    • Android Intent-এর স্বতন্ত্র ফিল্ড অ্যাসার্ট করুন।
    • intent.getData.getHost পদ্ধতির মাধ্যমে অ্যাক্সেস করা হয়েছে এমন ইনটেন্টের uri অ্যাসার্ট করুন।
  4. DEEPLINK কেসের জন্য, AppActionsFulfillmentResult-কে AppActionsIntentFulfillmentResult-এ টাইপকাস্ট করুন (উপরে INTENT পরিস্থিতির মতোই), getIntent পদ্ধতি কল করে Android ইনটেন্ট ফেচ করুন এবং ডিপলিঙ্ক URL (intent.getData.getHost-এর মাধ্যমে অ্যাক্সেস করা) অ্যাসার্ট করুন।
  5. INTENT এবং DEEPLINK, দুটির ক্ষেত্রেই আপনি বেছে নেওয়া Android টেস্টিং ফ্রেমওয়ার্কের মাধ্যমে অ্যাক্টিভিটি লঞ্চ করার জন্য ফলাফল হিসেবে পাওয়া ইনটেন্ট ব্যবহার করতে পারবেন।

ইন্টারন্যাশনালাইজেশন

আপনার অ্যাপে একাধিক লোকেল থাকলে, আপনি টেস্টের অধীনে একটি নির্দিষ্ট লোকেল চালানোর জন্য টেস্ট কনফিগার করতে পারেন। অন্যথায়, আপনি সরাসরি লোকেল পরিবর্তন করতে পারেন:

Kotlin

    
    import android.content.res.Configuration
    import java.util.Locale
    ...
    val newLocale = Locale("es")
    val conf = context.resources.configuration
    conf = Configuration(conf)
    conf.setLocale(newLocale)
    
  

জাভা

    
    Locale newLocale = new Locale("es");
    Configuration conf = context.getResources().getConfiguration();
    conf = new Configuration(conf);
    conf.setLocale(newLocale);
    
  

স্প্যানিশ (ES) লোকেলের জন্য কনফিগার করা AATL টেস্টের একটি উদাহরণ এখানে দেওয়া হল:

Kotlin

      
      import com.google.common.truth.Truth.assertThat
      import org.junit.Assert.assertEquals
      import android.content.Context
      import android.content.res.Configuration
      import androidx.test.platform.app.InstrumentationRegistry
      import com.google.assistant.appactions.testing.aatl.AppActionsTestManager
      import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentIntentResult
      import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentResult
      import com.google.assistant.appactions.testing.aatl.fulfillment.FulfillmentType
      import com.google.common.collect.ImmutableMap
      import java.util.Locale
      import org.junit.Before
      import org.junit.Test
      import org.junit.runner.RunWith
      import org.robolectric.RobolectricTestRunner

      @RunWith(RobolectricTestRunner::class)
      class ShortcutForDifferentLocaleTest {

        @Before
        fun setUp() {
          val context = InstrumentationRegistry.getInstrumentation().getContext()

          // change the device locale to 'es'
          val newLocale = Locale("es")
          val conf = context.resources.configuration
          conf = Configuration(conf)
          conf.setLocale(newLocale)

          val localizedContext = context.createConfigurationContext(conf)
        }

        @Test
        fun shortcutForDifferentLocale_succeeds() {
          val aatl = AppActionsTestManager(localizedContext)
          val intentName = "actions.intent.GET_EXERCISE_PLAN"
          val intentParams = ImmutableMap.of("exercisePlan.forExercise.name", "Running")

          val result = aatl.fulfill(intentName, intentParams)
          assertThat(result.getFulfillmentType()).isEqualTo(FulfillmentType.INTENT)

          val intentResult = result as AppActionsFulfillmentIntentResult

          assertThat(intentResult.getIntent().getData().toString())
            .isEqualTo("myexercise://browse?plan=running_weekly")
        }
      }
      
    

জাভা

      
      import static com.google.common.truth.Truth.assertThat;
      import static org.junit.Assert.assertEquals;

      import android.content.Context;
      import android.content.res.Configuration;
      import androidx.test.platform.app.InstrumentationRegistry;
      import com.google.assistant.appactions.testing.aatl.AppActionsTestManager;
      import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentIntentResult;
      import com.google.assistant.appactions.testing.aatl.fulfillment.AppActionsFulfillmentResult;
      import com.google.assistant.appactions.testing.aatl.fulfillment.FulfillmentType;
      import com.google.common.collect.ImmutableMap;
      import java.util.Locale;
      import org.junit.Before;
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.robolectric.RobolectricTestRunner;

      @Test
      public void shortcutForDifferentLocale_succeeds() throws Exception {
        Context context = InstrumentationRegistry.getInstrumentation().getContext();

        // change the device locale to 'es'
        Locale newLocale = new Locale("es");
        Configuration conf = context.getResources().getConfiguration();
        conf = new Configuration(conf);
        conf.setLocale(newLocale);

        Context localizedContext = context.createConfigurationContext(conf);

        AppActionsTestManager aatl = new AppActionsTestManager(localizedContext);
        String intentName = "actions.intent.GET_EXERCISE_PLAN";
        ImmutableMap<String, String> intentParams = ImmutableMap.of("exercisePlan.forExercise.name", "Running");

        AppActionsFulfillmentResult result = aatl.fulfill(intentName, intentParams);
        assertThat(result.getFulfillmentType()).isEqualTo(FulfillmentType.INTENT);

        AppActionsFulfillmentIntentResult intentResult = (AppActionsFulfillmentIntentResult) result;

        assertThat(intentResult.getIntent().getData().toString())
          .isEqualTo("myexercise://browse?plan=running_weekly");
      }
      
    

সমস্যার সমাধান করুন

আপনার ইন্টিগ্রেশন টেস্ট অপ্রত্যাশিতভাবে ব্যর্থ হলে, আপনি সতর্কতা বা ত্রুটি স্তরের মেসেজ পেতে Android Studio logcat উইন্ডোতে AATL লগ মেসেজ খুঁজতে পারেন। এছাড়াও, লাইব্রেরি থেকে আরও আউটপুট ক্যাপচার করতে আপনি লগিং লেভেল বাড়াতে পারেন।

সীমাবদ্ধতা

App Actions Test Library-র বর্তমান সীমাবদ্ধতাগুলি হল :

  • AATL ন্যাচারাল ল্যাঙ্গুয়েজ আন্ডারস্ট্যান্ডিং (NLU) বা স্পিচ-টু-টেক্সট (STT) ফিচার পরীক্ষা করে না।
  • ডিফল্ট অ্যাপ মডিউল ছাড়া অন্য মডিউলে পরীক্ষা করা হলে AATL কাজ করে না।
  • AATL শুধুমাত্র Android 7.0 "Nougat" (API লেভেল ২৪) এবং তার পরবর্তী ভার্সনের সাথে মানানসই।