টেস্টিং বেসিক

এই কোডল্যাবটি অ্যাডভান্সড অ্যান্ড্রয়েড ইন কোটলিন কোর্সের অংশ। আপনি যদি কোডল্যাবগুলি ক্রমানুসারে কাজ করেন তবে আপনি এই কোর্সের সর্বাধিক মূল্য পাবেন, তবে এটি বাধ্যতামূলক নয়৷ সমস্ত কোর্স কোডল্যাবগুলি কোটলিন কোডল্যাবস ল্যান্ডিং পৃষ্ঠায় অ্যাডভান্সড অ্যান্ড্রয়েডে তালিকাভুক্ত করা হয়েছে।

ভূমিকা

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

কম্পিউটারগুলি স্কেলিং এবং অটোমেশনে দুর্দান্ত! তাই বড় এবং ছোট কোম্পানিগুলির বিকাশকারীরা স্বয়ংক্রিয় পরীক্ষাগুলি লিখতে পারে, যা এমন পরীক্ষা যা সফ্টওয়্যার দ্বারা চালিত হয় এবং কোড কাজ করে যাচাই করার জন্য আপনাকে ম্যানুয়ালি অ্যাপটি পরিচালনা করতে হবে না।

কোডল্যাবগুলির এই সিরিজে আপনি যা শিখবেন তা হল কিভাবে একটি বাস্তব-বিশ্বের অ্যাপের জন্য পরীক্ষার একটি সংগ্রহ (একটি টেস্টিং স্যুট হিসাবে পরিচিত) তৈরি করতে হয়।

এই প্রথম কোডল্যাবটি অ্যান্ড্রয়েডে পরীক্ষার প্রাথমিক বিষয়গুলিকে কভার করে, আপনি আপনার প্রথম পরীক্ষাগুলি লিখবেন এবং কীভাবে LiveData এবং ViewModel s পরীক্ষা করতে হয় তা শিখবেন৷

আপনি ইতিমধ্যে কি জানা উচিত

আপনার সাথে পরিচিত হওয়া উচিত:

আপনি কি শিখবেন

আপনি নিম্নলিখিত বিষয়গুলি সম্পর্কে শিখবেন:

  • কীভাবে অ্যান্ড্রয়েডে ইউনিট পরীক্ষা লিখবেন এবং চালাবেন
  • টেস্ট ড্রাইভেন ডেভেলপমেন্ট কিভাবে ব্যবহার করবেন
  • যন্ত্রযুক্ত পরীক্ষা এবং স্থানীয় পরীক্ষাগুলি কীভাবে চয়ন করবেন

আপনি নিম্নলিখিত লাইব্রেরি এবং কোড ধারণা সম্পর্কে শিখবেন:

আপনি কি করবেন

  • অ্যান্ড্রয়েডে স্থানীয় এবং যন্ত্রযুক্ত উভয় পরীক্ষা সেট আপ করুন, চালান এবং ব্যাখ্যা করুন৷
  • JUnit4 এবং Hamcrest ব্যবহার করে অ্যান্ড্রয়েডে ইউনিট পরীক্ষা লিখুন।
  • সহজ LiveData এবং ViewModel পরীক্ষা লিখুন।

কোডল্যাবগুলির এই সিরিজে, আপনি TO-DO Notes অ্যাপের সাথে কাজ করবেন৷ অ্যাপটি আপনাকে কাজগুলি সম্পূর্ণ করার জন্য লিখতে দেয় এবং সেগুলিকে একটি তালিকায় প্রদর্শন করে৷ তারপরে আপনি সেগুলিকে সম্পূর্ণ বা না হিসাবে চিহ্নিত করতে পারেন, সেগুলিকে ফিল্টার করতে বা মুছতে পারেন৷

এই অ্যাপটি কোটলিনে লেখা, বেশ কয়েকটি স্ক্রিন রয়েছে, জেটপ্যাক উপাদান ব্যবহার করে এবং অ্যাপ আর্কিটেকচারের নির্দেশিকা থেকে আর্কিটেকচার অনুসরণ করে। এই অ্যাপটি কীভাবে পরীক্ষা করতে হয় তা শিখে, আপনি একই লাইব্রেরি এবং আর্কিটেকচার ব্যবহার করে এমন অ্যাপগুলি পরীক্ষা করতে সক্ষম হবেন।

শুরু করতে, কোড ডাউনলোড করুন:

জিপ ডাউনলোড করুন

বিকল্পভাবে, আপনি কোডের জন্য Github সংগ্রহস্থল ক্লোন করতে পারেন:

$ git clone https://github.com/googlecodelabs/android-testing.git
$ cd android-testing
$ git checkout starter_code

এই টাস্কে আপনি অ্যাপটি চালাবেন এবং কোড বেস অন্বেষণ করবেন।

ধাপ 1: নমুনা অ্যাপ চালান

একবার আপনি TO-DO অ্যাপটি ডাউনলোড করলে, এটিকে অ্যান্ড্রয়েড স্টুডিওতে খুলুন এবং এটি চালান। এটা কম্পাইল করা উচিত. নিম্নলিখিতগুলি করে অ্যাপটি অন্বেষণ করুন:

  • প্লাস ফ্লোটিং অ্যাকশন বোতাম দিয়ে একটি নতুন টাস্ক তৈরি করুন। প্রথমে একটি শিরোনাম লিখুন, তারপর টাস্ক সম্পর্কে অতিরিক্ত তথ্য লিখুন। সবুজ চেক FAB দিয়ে এটি সংরক্ষণ করুন।
  • কাজের তালিকায়, আপনি যে কাজটি সম্পূর্ণ করেছেন তার শিরোনামে ক্লিক করুন এবং বাকি বিবরণ দেখতে সেই কাজের জন্য বিস্তারিত স্ক্রীনটি দেখুন।
  • তালিকায় বা বিশদ স্ক্রিনে, সেই টাস্কটির স্থিতি সম্পূর্ণ করতে সেট করতে তার চেকবক্সটি চেক করুন।
  • টাস্ক স্ক্রিনে ফিরে যান, ফিল্টার মেনু খুলুন এবং সক্রিয় এবং সম্পূর্ণ স্থিতি দ্বারা কাজগুলি ফিল্টার করুন।
  • নেভিগেশন ড্রয়ার খুলুন এবং পরিসংখ্যান ক্লিক করুন।
  • ওভারভিউ স্ক্রিনে ফিরে আসি, এবং নেভিগেশন ড্রয়ার মেনু থেকে, সম্পূর্ণ স্থিতি সহ সমস্ত কাজ মুছে ফেলতে সাফ সম্পন্ন নির্বাচন করুন

ধাপ 2: নমুনা অ্যাপ কোড অন্বেষণ করুন

TO-DO অ্যাপটি জনপ্রিয় আর্কিটেকচার ব্লুপ্রিন্ট টেস্টিং এবং আর্কিটেকচার নমুনা (নমুনার প্রতিক্রিয়াশীল আর্কিটেকচার সংস্করণ ব্যবহার করে) এর উপর ভিত্তি করে তৈরি। অ্যাপটি একটি গাইড থেকে অ্যাপ আর্কিটেকচারের আর্কিটেকচার অনুসরণ করে। এটি ফ্র্যাগমেন্টস, একটি সংগ্রহস্থল এবং রুম সহ ভিউ মডেল ব্যবহার করে। আপনি যদি নীচের উদাহরণগুলির সাথে পরিচিত হন তবে এই অ্যাপটির একটি অনুরূপ আর্কিটেকচার রয়েছে:

যেকোন একটি স্তরে যুক্তির গভীর বোঝার চেয়ে অ্যাপটির সাধারণ আর্কিটেকচার বোঝা বেশি গুরুত্বপূর্ণ।

এখানে আপনি যে প্যাকেজগুলি পাবেন তার সারাংশ:

প্যাকেজ: com.example.android.architecture.blueprints.todoapp

.addedittask

একটি টাস্ক স্ক্রীন যোগ বা সম্পাদনা করুন: একটি টাস্ক যোগ বা সম্পাদনা করার জন্য UI স্তর কোড।

.data

ডাটা লেয়ার: এটি কাজের ডাটা লেয়ার নিয়ে কাজ করে। এতে ডাটাবেস, নেটওয়ার্ক এবং রিপোজিটরি কোড রয়েছে।

.statistics

পরিসংখ্যান স্ক্রীন: পরিসংখ্যান পর্দার জন্য UI স্তর কোড।

.taskdetail

টাস্ক ডিটেইল স্ক্রিন: একটি টাস্কের জন্য UI লেয়ার কোড।

.tasks

টাস্ক স্ক্রিন: সমস্ত কাজের তালিকার জন্য UI লেয়ার কোড।

.util

ইউটিলিটি ক্লাস: অ্যাপের বিভিন্ন অংশে ব্যবহৃত শেয়ার্ড ক্লাস, যেমন একাধিক স্ক্রিনে ব্যবহৃত সোয়াইপ রিফ্রেশ লেআউটের জন্য।

ডেটা স্তর (.ডেটা)

এই অ্যাপটিতে একটি সিমুলেটেড নেটওয়ার্কিং স্তর রয়েছে, দূরবর্তী প্যাকেজে এবং স্থানীয় প্যাকেজে একটি ডাটাবেস স্তর রয়েছে৷ সরলতার জন্য, এই প্রজেক্টে নেটওয়ার্কিং লেয়ারটি সত্যিকারের নেটওয়ার্ক অনুরোধ করার পরিবর্তে বিলম্বের সাথে একটি HashMap দিয়ে সিমুলেট করা হয়েছে।

DefaultTasksRepository নেটওয়ার্কিং স্তর এবং ডাটাবেস স্তরের মধ্যে সমন্বয় বা মধ্যস্থতা করে এবং এটিই UI স্তরে ডেটা ফেরত দেয়।

UI স্তর (.addedittask, .statistics, .taskdetail, .tasks)

প্রতিটি UI লেয়ার প্যাকেজে একটি টুকরো এবং একটি ভিউ মডেল রয়েছে, সাথে অন্য যেকোন ক্লাস যা UI এর জন্য প্রয়োজনীয় (যেমন টাস্ক লিস্টের জন্য অ্যাডাপ্টার)। TaskActivity হল সেই ক্রিয়াকলাপ যাতে সমস্ত অংশ থাকে।

নেভিগেশন

অ্যাপের জন্য নেভিগেশন নেভিগেশন উপাদান দ্বারা নিয়ন্ত্রিত হয়। এটি nav_graph.xml ফাইলে সংজ্ঞায়িত করা হয়েছে। Event ক্লাস ব্যবহার করে ভিউ মডেলগুলিতে নেভিগেশন ট্রিগার করা হয়; ভিউ মডেলগুলিও নির্ধারণ করে যে কোন আর্গুমেন্টগুলি পাস করতে হবে। Event ইভেন্টগুলি পর্যবেক্ষণ করে এবং পর্দার মধ্যে প্রকৃত নেভিগেশন করে।

এই টাস্কে, আপনি আপনার প্রথম পরীক্ষা চালাবেন।

  1. অ্যান্ড্রয়েড স্টুডিওতে, প্রকল্প ফলক খুলুন এবং এই তিনটি ফোল্ডার খুঁজুন:
  • com.example.android.architecture.blueprints.todoapp
  • com.example.android.architecture.blueprints.todoapp (androidTest)
  • com.example.android.architecture.blueprints.todoapp (test)

এই ফোল্ডারগুলি সোর্স সেট হিসাবে পরিচিত। সোর্স সেট হল আপনার অ্যাপের সোর্স কোড ধারণকারী ফোল্ডার। সোর্স সেটগুলি, যেগুলি রঙিন সবুজ ( androidTest এবং test ) আপনার পরীক্ষাগুলি ধারণ করে৷ আপনি যখন একটি নতুন অ্যান্ড্রয়েড প্রকল্প তৈরি করেন, আপনি ডিফল্টরূপে নিম্নলিখিত তিনটি উৎস সেট পাবেন৷ তারা হল:

  • main : আপনার অ্যাপ কোড রয়েছে। এই কোডটি আপনি তৈরি করতে পারেন এমন অ্যাপের বিভিন্ন সংস্করণের মধ্যে ভাগ করা হয়েছে ( বিল্ড ভেরিয়েন্ট হিসাবে পরিচিত)
  • androidTest : ইন্সট্রুমেন্টেড টেস্ট নামে পরিচিত পরীক্ষা রয়েছে।
  • test : স্থানীয় পরীক্ষা হিসাবে পরিচিত পরীক্ষা রয়েছে।

স্থানীয় পরীক্ষা এবং যন্ত্রযুক্ত পরীক্ষার মধ্যে পার্থক্য হল সেগুলি চালানোর পদ্ধতিতে।

স্থানীয় পরীক্ষা ( test উত্স সেট)

এই পরীক্ষাগুলি স্থানীয়ভাবে আপনার ডেভেলপমেন্ট মেশিনের JVM-এ চালানো হয় এবং এর জন্য কোনো এমুলেটর বা শারীরিক ডিভাইসের প্রয়োজন হয় না। এই কারণে, তারা দ্রুত দৌড়ায়, কিন্তু তাদের বিশ্বস্ততা কম, যার অর্থ তারা বাস্তব জগতের মতো কম কাজ করে।

অ্যান্ড্রয়েড স্টুডিওতে স্থানীয় পরীক্ষাগুলি একটি সবুজ এবং লাল ত্রিভুজ আইকন দ্বারা উপস্থাপিত হয়।

ইন্সট্রুমেন্টেড টেস্ট ( androidTest সোর্স সেট)

এই পরীক্ষাগুলি বাস্তব বা অনুকরণ করা অ্যান্ড্রয়েড ডিভাইসগুলিতে চালিত হয়, তাই তারা বাস্তব জগতে কী ঘটবে তা প্রতিফলিত করে, তবে এটি অনেক ধীর।

অ্যান্ড্রয়েড স্টুডিওতে ইনস্ট্রুমেন্টেড পরীক্ষাগুলি একটি সবুজ এবং লাল ত্রিভুজ আইকন সহ একটি অ্যান্ড্রয়েড দ্বারা উপস্থাপিত হয়।

ধাপ 1: একটি স্থানীয় পরীক্ষা চালান

  1. আপনি ExampleUnitTest.kt ফাইলটি না পাওয়া পর্যন্ত test ফোল্ডারটি খুলুন।
  2. এটিতে ডান-ক্লিক করুন এবং ExampleUnitTest চালান নির্বাচন করুন।

আপনি পর্দার নীচে রান উইন্ডোতে নিম্নলিখিত আউটপুট দেখতে হবে:

  1. সবুজ চেকমার্কগুলি লক্ষ্য করুন এবং addition_isCorrect নামক একটি পরীক্ষা পাস হয়েছে তা নিশ্চিত করতে পরীক্ষার ফলাফলগুলি প্রসারিত করুন। এটা জানা ভাল যে সংযোজন প্রত্যাশিত হিসাবে কাজ করে!

ধাপ 2: পরীক্ষা ব্যর্থ করুন

নীচে আপনি এইমাত্র দৌড়েছেন এমন পরীক্ষা।

ExampleUnitTest.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 টীকা দিয়ে শুরু হওয়া ফাংশনগুলি রয়েছে (প্রতিটি ফাংশন একটি একক পরীক্ষা)।
  • u8 সাধারণত দাবী বিবৃতি ধারণ করে।

অ্যান্ড্রয়েড পরীক্ষার জন্য পরীক্ষামূলক লাইব্রেরি JUnit ব্যবহার করে (এই কোডল্যাবে JUnit4)। উভয়, দাবী এবং @Test টীকা JUnit থেকে এসেছে।

একটি দাবী আপনার পরীক্ষার মূল. এটি একটি কোড বিবৃতি যা পরীক্ষা করে যে আপনার কোড বা অ্যাপটি প্রত্যাশা অনুযায়ী আচরণ করেছে। এই ক্ষেত্রে, দাবিটি assertEquals(4, 2 + 2) যা পরীক্ষা করে যে 4 2 + 2 এর সমান।

একটি ব্যর্থ পরীক্ষা কেমন দেখায় তা দেখতে একটি দাবি যোগ করুন যা আপনি সহজেই দেখতে পাচ্ছেন ব্যর্থ হওয়া উচিত। এটা চেক করবে যে 3 সমান 1+1।

  1. assertEquals(3, 1 + 1) addition_isCorrect করুন।

ExampleUnitTest.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
   }
}
  1. পরীক্ষা চালান।
  1. পরীক্ষার ফলাফলে, পরীক্ষার পাশে একটি X লক্ষ্য করুন।

  1. এছাড়াও লক্ষ্য করুন:
  • একটি একক ব্যর্থ দাবি পুরো পরীক্ষায় ব্যর্থ হয়।
  • আপনাকে বলা হয়েছে প্রত্যাশিত মান (3) বনাম যে মানটি আসলে গণনা করা হয়েছিল (2)।
  • আপনাকে ব্যর্থ দাবির লাইনে নির্দেশিত করা হয়েছে (ExampleUnitTest.kt:16)

ধাপ 3: একটি যন্ত্রযুক্ত পরীক্ষা চালান

যন্ত্রযুক্ত পরীক্ষাগুলি androidTest উত্স সেটে রয়েছে৷

  1. androidTest সোর্স সেটটি খুলুন।
  2. ExampleInstrumentedTest নামক পরীক্ষাটি চালান।

উদাহরণ ইন্সট্রুমেন্টেড টেস্ট

@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: একটি পরীক্ষা ক্লাস তৈরি করুন

  1. main উৎস সেটে, todoapp.statistics এ, StatisticsUtils.kt খুলুন।
  2. getActiveAndCompletedStats ফাংশন খুঁজুন।

StatisticsUtils.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 ফাংশনটি কাজের একটি তালিকা গ্রহণ করে এবং একটি StatsResultStatsResult হল একটি ডেটা ক্লাস যাতে দুটি সংখ্যা থাকে, যেগুলি কাজ শেষ হয়েছে তার শতাংশ এবং সক্রিয় শতাংশ।

অ্যান্ড্রয়েড স্টুডিও আপনাকে এই ফাংশনের জন্য পরীক্ষাগুলি বাস্তবায়ন করতে সহায়তা করে টেস্ট স্টাব তৈরি করতে আপনাকে টুল দেয়।

  1. getActiveAndCompletedStats রাইট ক্লিক করুন এবং Generate > Test নির্বাচন করুন।

টেস্ট তৈরি করুন ডায়ালগ খোলে:

  1. ক্লাসের নাম পরিবর্তন করুন: StatisticsUtilsTest ( StatisticsUtilsKtTest এর পরিবর্তে; পরীক্ষার ক্লাসের নামে KT না থাকাটা একটু ভালো)।
  2. বাকি ডিফল্ট রাখুন। JUnit 4 উপযুক্ত পরীক্ষার লাইব্রেরি। গন্তব্য প্যাকেজটি সঠিক (এটি StatisticsUtils ক্লাসের অবস্থানকে মিরর করে) এবং আপনাকে কোনো চেক বক্স চেক করার দরকার নেই (এটি শুধুমাত্র অতিরিক্ত কোড তৈরি করে, কিন্তু আপনি স্ক্র্যাচ থেকে আপনার পরীক্ষা লিখবেন)।
  3. ঠিক আছে টিপুন

গন্তব্য ডিরেক্টরি নির্বাচন করুন ডায়ালগ খোলে:

আপনি একটি স্থানীয় পরীক্ষা করবেন কারণ আপনার ফাংশন গণিত গণনা করছে এবং কোনো Android নির্দিষ্ট কোড অন্তর্ভুক্ত করবে না। সুতরাং, এটি একটি বাস্তব বা অনুকরণ করা ডিভাইসে চালানোর কোন প্রয়োজন নেই।

  1. test ডিরেক্টরি নির্বাচন করুন ( androidTest নয়) কারণ আপনি স্থানীয় পরীক্ষা লিখবেন।
  2. ঠিক আছে ক্লিক করুন.
  3. test/statistics/ StatisticsUtilsTest ক্লাস তৈরি করা লক্ষ্য করুন।

ধাপ 2: আপনার প্রথম পরীক্ষা ফাংশন লিখুন

আপনি একটি পরীক্ষা লিখতে যাচ্ছেন যা পরীক্ষা করে:

  • যদি কোন সমাপ্ত কাজ এবং একটি সক্রিয় কাজ না থাকে,
  • যে সক্রিয় পরীক্ষার শতাংশ 100%,
  • এবং সমাপ্ত কাজের শতাংশ হল 0%।
  1. StatisticsUtilsTest খুলুন।
  2. getActiveAndCompletedStats_noCompleted_returnsHundredZero নামে একটি ফাংশন তৈরি করুন।

StatisticsUtilsTest.kt

class StatisticsUtilsTest {

    fun getActiveAndCompletedStats_noCompleted_returnsHundredZero() {
        // Create an active task

        // Call your function

        // Check the result
    }
}
  1. এটি একটি পরীক্ষা নির্দেশ করতে ফাংশনের নামের উপরে @Test টীকা যোগ করুন।
  2. কাজের একটি তালিকা তৈরি করুন।
// Create an active task 
val tasks = listOf<Task>(
            Task("title", "desc", isCompleted = false)
        )
  1. এই কাজগুলির সাথে getActiveAndCompletedStats কল করুন।
// Call your function
val result = getActiveAndCompletedStats(tasks)
  1. result ব্যবহার করে, আপনি যা আশা করেছিলেন তা পরীক্ষা করুন।
// Check the result
assertEquals(result.completedTasksPercent, 0f)
assertEquals(result.activeTasksPercent, 100f)

এখানে সম্পূর্ণ কোড আছে.

StatisticsUtilsTest.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)
    }
}
  1. পরীক্ষা চালান (রাইট ক্লিক করুন StatisticsUtilsTest এবং রান নির্বাচন করুন)।

এটি পাস করা উচিত:

ধাপ 3: হ্যামক্রেস্ট নির্ভরতা যোগ করুন

যেহেতু আপনার পরীক্ষাগুলি আপনার কোড যা করে তার ডকুমেন্টেশন হিসাবে কাজ করে, সেগুলি মানুষের পঠনযোগ্য হলে এটি চমৎকার। নিম্নলিখিত দুটি দাবী তুলনা করুন:

assertEquals(result.completedTasksPercent, 0f)

// versus

assertThat(result.completedTasksPercent, `is`(0f))

দ্বিতীয় দাবীটি মানুষের বাক্যের মতো অনেক বেশি পড়ে। এটি হ্যামক্রেস্ট নামে একটি দাবী কাঠামো ব্যবহার করে লেখা হয়েছে। পঠনযোগ্য দাবী লেখার আরেকটি ভালো হাতিয়ার হল ট্রুথ লাইব্রেরি । আপনি দাবী লিখতে এই কোডল্যাবে হ্যামক্রেস্ট ব্যবহার করবেন।

  1. 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: দাবী লিখতে হ্যামক্রেস্ট ব্যবহার করুন

  1. assertEquals এর পরিবর্তে assertEquals এর assertThat ব্যবহার করতে getActiveAndCompletedStats_noCompleted_returnsHundredZero() পরীক্ষা আপডেট করুন।
// 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` ব্যবহার করতে পারেন যদি অনুরোধ করা হয়।

চূড়ান্ত পরীক্ষা নীচের কোড মত দেখাবে.

StatisticsUtilsTest.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))

    }
}
  1. এটি এখনও কাজ করে তা নিশ্চিত করতে আপনার আপডেট করা পরীক্ষা চালান!

এই কোডল্যাব আপনাকে হ্যামক্রেস্টের সমস্ত ইনস এবং আউটগুলি শেখাবে না , তাই আপনি যদি আরও শিখতে চান তবে অফিসিয়াল টিউটোরিয়ালটি দেখুন

এটি অনুশীলনের জন্য একটি ঐচ্ছিক কাজ।

এই টাস্কে, আপনি JUnit এবং Hamcrest ব্যবহার করে আরও পরীক্ষা লিখবেন। এছাড়াও আপনি টেস্ট ড্রাইভেন ডেভেলপমেন্টের প্রোগ্রাম অনুশীলন থেকে প্রাপ্ত একটি কৌশল ব্যবহার করে পরীক্ষা লিখবেন। টেস্ট ড্রাইভেন ডেভেলপমেন্ট বা TDD হল প্রোগ্রামিং চিন্তার একটি স্কুল যা বলে আপনার বৈশিষ্ট্য কোড প্রথমে লেখার পরিবর্তে, আপনি প্রথমে আপনার পরীক্ষাগুলি লিখুন। তারপর আপনি আপনার পরীক্ষা পাস করার লক্ষ্য সঙ্গে আপনার বৈশিষ্ট্য কোড লিখুন.

ধাপ 1. পরীক্ষা লিখুন

যখন আপনার একটি স্বাভাবিক কাজের তালিকা থাকবে তার জন্য পরীক্ষা লিখুন:

  1. যদি একটি সম্পূর্ণ টাস্ক থাকে এবং কোন সক্রিয় টাস্ক না থাকে, তাহলে activeTasks শতাংশ 0f হওয়া উচিত, এবং সম্পূর্ণ করা টাস্কের শতাংশ 100f হওয়া উচিত।
  2. দুটি সম্পূর্ণ কাজ এবং তিনটি সক্রিয় কাজ থাকলে, সম্পূর্ণ শতাংশ 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()
   )
  
}

কোড ঠিক করতে এবং পরীক্ষা লিখতে, আপনি পরীক্ষা চালিত বিকাশ ব্যবহার করবেন। টেস্ট চালিত উন্নয়ন এই পদক্ষেপগুলি অনুসরণ করে।

  1. দেওয়া, কখন, তারপর গঠন ব্যবহার করে এবং নিয়ম অনুসরণ করে এমন একটি নাম দিয়ে পরীক্ষাটি লিখুন।
  2. পরীক্ষা ব্যর্থ নিশ্চিত করুন.
  3. পরীক্ষায় উত্তীর্ণ হওয়ার জন্য সর্বনিম্ন কোডটি লিখুন।
  4. সব পরীক্ষার জন্য পুনরাবৃত্তি!

বাগ সংশোধন করে শুরু করার পরিবর্তে, আপনি প্রথমে পরীক্ষা লিখে শুরু করবেন। তারপর আপনি নিশ্চিত করতে পারেন যে আপনার পরীক্ষা আছে যা আপনাকে ভুলবশত ভবিষ্যতে এই বাগগুলিকে পুনরায় প্রবর্তন করা থেকে রক্ষা করবে।

  1. যদি একটি খালি তালিকা থাকে ( emptyList() ), তাহলে উভয় শতাংশই 0f হওয়া উচিত।
  2. যদি কাজগুলি লোড করার সময় একটি ত্রুটি থাকে তবে তালিকাটি শূন্য হবে এবং উভয় শতাংশই null হওয়া উচিত৷
  3. আপনার পরীক্ষা চালান এবং নিশ্চিত করুন যে তারা ব্যর্থ হয়েছে:

ধাপ 3. বাগ ঠিক করুন

এখন আপনার পরীক্ষা আছে, বাগ ঠিক করুন।

  1. যদি tasks শূন্য বা null থাকে তবে 0f ফেরত দিয়ে getActiveAndCompletedStats এ বাগটি ঠিক করুন:
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
        )
    }
}
  1. আবার আপনার পরীক্ষা চালান এবং নিশ্চিত করুন যে সমস্ত পরীক্ষা এখন পাস!

TDD অনুসরণ করে এবং প্রথমে পরীক্ষা লিখে, আপনি নিশ্চিত করতে সাহায্য করেছেন যে:

  • নতুন কার্যকারিতা সবসময় সংশ্লিষ্ট পরীক্ষা আছে; এইভাবে আপনার পরীক্ষাগুলি আপনার কোড যা করে তার ডকুমেন্টেশন হিসাবে কাজ করে।
  • আপনার পরীক্ষাগুলি সঠিক ফলাফলের জন্য পরীক্ষা করে এবং আপনি ইতিমধ্যে দেখেছেন এমন বাগগুলি থেকে রক্ষা করে৷

সমাধান: আরও পরীক্ষা লেখা

এখানে সব পরীক্ষা এবং সংশ্লিষ্ট বৈশিষ্ট্য কোড আছে.

StatisticsUtilsTest.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))
    }
}

StatisticsUtils.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 পরীক্ষা লিখতে হয়।

কোডল্যাবের বাকি অংশে, আপনি শিখবেন কীভাবে দুটি অ্যান্ড্রয়েড ক্লাসের জন্য পরীক্ষা লিখতে হয় যা বেশিরভাগ অ্যাপ- ViewModel এবং LiveData জুড়ে সাধারণ।

আপনি TasksViewModel এর জন্য পরীক্ষা লিখে শুরু করেন।


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



আপনি যে পরীক্ষাটি লিখবেন তা পরীক্ষা করবে যে আপনি যখন addNewTask পদ্ধতিতে কল করবেন, তখন নতুন টাস্ক উইন্ডো খোলার Event বরখাস্ত হয়েছে। আপনি যে অ্যাপ কোডটি পরীক্ষা করবেন তা এখানে।

TasksViewModel.kt

fun addNewTask() {
   _newTaskEvent.value = Event(Unit)
}

ধাপ 1. একটি TasksViewModelTest ক্লাস তৈরি করুন

আপনি StatisticsUtilTest এর জন্য একই পদক্ষেপগুলি অনুসরণ করে, এই ধাপে, আপনি TasksViewModelTest জন্য একটি পরীক্ষা ফাইল তৈরি করুন।

  1. আপনি যে ক্লাসটি পরীক্ষা করতে চান সেটি খুলুন, tasks প্যাকেজে, TasksViewModel.
  2. কোডে, TasksViewModel -> Generate -> Test ক্লাসের নামের উপর রাইট-ক্লিক করুন।

  1. পরীক্ষা তৈরি করুন স্ক্রিনে, গ্রহণ করতে ঠিক আছে ক্লিক করুন (ডিফল্ট সেটিংস পরিবর্তন করার প্রয়োজন নেই)।
  2. গন্তব্য ডিরেক্টরি নির্বাচন করুন ডায়ালগে, পরীক্ষা ডিরেক্টরি নির্বাচন করুন।

ধাপ 2. আপনার ভিউমডেল পরীক্ষা লেখা শুরু করুন

এই ধাপে আপনি একটি ভিউ মডেল টেস্ট যোগ করেন পরীক্ষা করার জন্য যে আপনি যখন addNewTask পদ্ধতিতে কল করেন, তখন নতুন টাস্ক উইন্ডো খোলার Event বরখাস্ত হয়।

  1. 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 এর একটি উদাহরণ তৈরি করেন, তখন এর কনস্ট্রাক্টরের একটি অ্যাপ্লিকেশন প্রসঙ্গ প্রয়োজন। কিন্তু এই পরীক্ষায়, আপনি ক্রিয়াকলাপ এবং UI এবং টুকরো দিয়ে একটি সম্পূর্ণ অ্যাপ্লিকেশন তৈরি করছেন না, তাহলে আপনি কীভাবে একটি অ্যাপ্লিকেশন প্রসঙ্গ পাবেন?

TasksViewModelTest.kt

// Given a fresh ViewModel
        val tasksViewModel = TasksViewModel(???)

অ্যান্ড্রয়েডএক্স টেস্ট লাইব্রেরিগুলিতে ক্লাস এবং পদ্ধতিগুলি অন্তর্ভুক্ত রয়েছে যা আপনাকে অ্যাপ্লিকেশন এবং অ্যাক্টিভিটিগুলির মতো উপাদানগুলির সংস্করণ সরবরাহ করে যা পরীক্ষার জন্য তৈরি। যখন আপনার একটি স্থানীয় পরীক্ষা থাকে যেখানে আপনার সিমুলেটেড অ্যান্ড্রয়েড ফ্রেমওয়ার্ক ক্লাসের প্রয়োজন হয় (যেমন একটি অ্যাপ্লিকেশন প্রসঙ্গ), সঠিকভাবে AndroidX টেস্ট সেট আপ করতে এই পদক্ষেপগুলি অনুসরণ করুন:

  1. AndroidX টেস্ট কোর এবং এক্সট নির্ভরতা যোগ করুন
  2. রোবোলেক্ট্রিক টেস্টিং লাইব্রেরি নির্ভরতা যোগ করুন
  3. AndroidJunit4 টেস্ট রানার দিয়ে ক্লাসটি টীকা করুন
  4. AndroidX টেস্ট কোড লিখুন

আপনি এই পদক্ষেপগুলি সম্পূর্ণ করতে যাচ্ছেন এবং তারপরে বুঝতে পারবেন তারা একসাথে কী করে।

ধাপ 3. গ্রেডেল নির্ভরতা যোগ করুন

  1. আপনার অ্যাপ মডিউলের build.gradle ফাইলে এই নির্ভরতাগুলি অনুলিপি করুন মূল AndroidX টেস্ট কোর এবং ext নির্ভরতা, পাশাপাশি Roboelectric testing নির্ভরতা যোগ করতে।

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. জুনিট টেস্ট রানার যোগ করুন

  1. আপনার পরীক্ষার ক্লাসের উপরে @RunWith(AndroidJUnit4::class) যোগ করুন।

TasksViewModelTest.kt

@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {
    // Test code
}

ধাপ 5. AndroidX পরীক্ষা ব্যবহার করুন

এই মুহুর্তে, আপনি AndroidX টেস্ট লাইব্রেরি ব্যবহার করতে পারেন। এর মধ্যে রয়েছে ApplicationProvider.getApplicationContex t পদ্ধতি, যা একটি অ্যাপ্লিকেশন প্রসঙ্গ পায়।

  1. AndroidX পরীক্ষা লাইব্রেরি থেকে ApplicationProvider.getApplicationContext() ব্যবহার করে একটি TasksViewModel তৈরি করুন।

TasksViewModelTest.kt

// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
  1. addNewTasktasksViewModel কল করুন।

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
    }
  1. এটি কাজ করে তা নিশ্চিত করতে আপনার পরীক্ষা চালান

ধারণা: AndroidX পরীক্ষা কিভাবে কাজ করে?

AndroidX পরীক্ষা কি?

AndroidX টেস্ট পরীক্ষার জন্য লাইব্রেরির একটি সংগ্রহ। এটিতে ক্লাস এবং পদ্ধতিগুলি অন্তর্ভুক্ত রয়েছে যা আপনাকে অ্যাপ্লিকেশন এবং অ্যাক্টিভিটিগুলির মতো উপাদানগুলির সংস্করণ দেয়, যা পরীক্ষার জন্য। একটি উদাহরণ হিসাবে, আপনার লেখা এই কোডটি একটি অ্যাপ্লিকেশন প্রসঙ্গ পাওয়ার জন্য একটি AndroidX টেস্ট ফাংশনের একটি উদাহরণ৷

ApplicationProvider.getApplicationContext()

অ্যান্ড্রয়েডএক্স টেস্ট এপিআইগুলির একটি সুবিধা হল যে এগুলি স্থানীয় পরীক্ষা এবং যন্ত্রযুক্ত পরীক্ষার জন্য কাজ করার জন্য তৈরি করা হয়েছে। এটি চমৎকার কারণ:

  • আপনি স্থানীয় পরীক্ষা বা যন্ত্রযুক্ত পরীক্ষার মতো একই পরীক্ষা চালাতে পারেন।
  • স্থানীয় বনাম ইন্সট্রুমেন্টেড পরীক্ষার জন্য আপনাকে বিভিন্ন টেস্টিং API শিখতে হবে না।

উদাহরণস্বরূপ, যেহেতু আপনি AndroidX টেস্ট লাইব্রেরি ব্যবহার করে আপনার কোড লিখেছেন, আপনি আপনার TasksViewModelTest test ফোল্ডার থেকে androidTest ফোল্ডারে সরাতে পারেন এবং পরীক্ষাগুলি এখনও চলবে৷ getApplicationContext() এটি স্থানীয় বা যন্ত্রযুক্ত পরীক্ষা হিসাবে চালানো হচ্ছে কিনা তার উপর নির্ভর করে কিছুটা ভিন্নভাবে কাজ করে:

  • যদি এটি একটি ইন্সট্রুমেন্টেড পরীক্ষা হয়, এটি একটি এমুলেটর বুট করার সময় বা একটি বাস্তব ডিভাইসের সাথে সংযোগ করার সময় প্রদান করা প্রকৃত অ্যাপ্লিকেশন প্রসঙ্গ পাবে।
  • এটি একটি স্থানীয় পরীক্ষা হলে, এটি একটি সিমুলেটেড অ্যান্ড্রয়েড পরিবেশ ব্যবহার করে।

Roboelectric কি?

স্থানীয় পরীক্ষার জন্য AndroidX টেস্ট যে সিমুলেটেড অ্যান্ড্রয়েড পরিবেশ ব্যবহার করে তা রোবোলেক্ট্রিক দ্বারা সরবরাহ করা হয়েছে। রোবোলেক্ট্রিক হল একটি লাইব্রেরি যা পরীক্ষার জন্য একটি সিমুলেটেড অ্যান্ড্রয়েড পরিবেশ তৈরি করে এবং এমুলেটর বুট করার বা ডিভাইসে চালানোর চেয়ে দ্রুত চলে। Roboelectric নির্ভরতা ছাড়া, আপনি এই ত্রুটি পাবেন:

@RunWith(AndroidJUnit4::class) কি করে?

একজন টেস্ট রানার একটি JUnit উপাদান যা পরীক্ষা চালায়। একটি পরীক্ষা রানার ছাড়া, আপনার পরীক্ষা চালানো হবে না. JUnit দ্বারা প্রদত্ত একটি ডিফল্ট পরীক্ষা রানার রয়েছে যা আপনি স্বয়ংক্রিয়ভাবে পাবেন। @RunWith সেই ডিফল্ট টেস্ট রানারকে অদলবদল করে।

AndroidJUnit4 টেস্ট রানার AndroidX টেস্টকে আপনার পরীক্ষাটি ভিন্নভাবে চালানোর অনুমতি দেয় যেগুলি যন্ত্রযুক্ত বা স্থানীয় পরীক্ষা কিনা তার উপর নির্ভর করে।

ধাপ 6. রোবোলেক্ট্রিক সতর্কতা ঠিক করুন

আপনি যখন কোডটি চালান, লক্ষ্য করুন যে Roboelectric ব্যবহার করা হয়েছে।

অ্যান্ড্রয়েডএক্স টেস্ট এবং অ্যান্ড্রয়েডজুনিট4 টেস্ট রানারের কারণে, এটি আপনাকে সরাসরি রোবোলেক্ট্রিক কোডের একটি লাইন না লিখেই করা হয়!

আপনি দুটি সতর্কতা লক্ষ্য করতে পারেন।

  • No such manifest file: ./AndroidManifest.xml
  • "WARN: Android SDK 29 requires Java 9..."

আপনি আপনার গ্রেডল ফাইল আপডেট করে No such manifest file: ./AndroidManifest.xml সতর্কতা।

  1. আপনার গ্রেডল ফাইলে নিম্নলিখিত লাইনটি যোগ করুন যাতে সঠিক অ্যান্ড্রয়েড ম্যানিফেস্ট ব্যবহার করা হয়। IncludeAndroidResources বিকল্প আপনাকে আপনার অ্যান্ড্রয়েড ম্যানিফেস্ট ফাইল সহ আপনার ইউনিট পরীক্ষায় অ্যান্ড্রয়েড রিসোর্স অ্যাক্সেস করতে দেয়।

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 প্রয়োজন । জাভা 9 ব্যবহার করার জন্য Android স্টুডিও কনফিগার করার চেষ্টা করার পরিবর্তে, এই কোডল্যাবের জন্য, আপনার লক্ষ্য রাখুন এবং 28 এ SDK কম্পাইল করুন।

সংক্ষেপে:

  • বিশুদ্ধ ভিউ মডেল পরীক্ষাগুলি সাধারণত test উত্স সেটে যেতে পারে কারণ তাদের কোডের জন্য সাধারণত অ্যান্ড্রয়েডের প্রয়োজন হয় না।
  • আপনি অ্যাপ্লিকেশন এবং ক্রিয়াকলাপগুলির মতো উপাদানগুলির পরীক্ষামূলক সংস্করণ পেতে AndroidX পরীক্ষা লাইব্রেরি ব্যবহার করতে পারেন৷
  • আপনি যদি আপনার test উত্স সেটে সিমুলেটেড অ্যান্ড্রয়েড কোড চালাতে চান তবে আপনি রোবোলেক্ট্রিক নির্ভরতা এবং @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 পরীক্ষা করার জন্য আপনাকে দুটি জিনিস করার পরামর্শ দেওয়া হচ্ছে:

  1. InstantTaskExecutorRule ব্যবহার করুন
  2. LiveData পর্যবেক্ষণ নিশ্চিত করুন

ধাপ 1. InstantTaskExecutorRule ব্যবহার করুন

InstantTaskExecutorRule হল একটি JUnit নিয়ম । আপনি যখন এটিকে @get:Rule টীকা দিয়ে ব্যবহার করেন, এটি InstantTaskExecutorRule ক্লাসে কিছু কোড পরীক্ষার আগে এবং পরে চালানোর কারণ হয় (সঠিক কোড দেখতে, আপনি ফাইলটি দেখতে কীবোর্ড শর্টকাট কমান্ড+বি ব্যবহার করতে পারেন)।

এই নিয়মটি একই থ্রেডে সমস্ত আর্কিটেকচার উপাদান-সম্পর্কিত পটভূমি কাজ চালায় যাতে পরীক্ষার ফলাফলগুলি সিঙ্ক্রোনাসভাবে এবং পুনরাবৃত্তিযোগ্য ক্রমে ঘটে। আপনি যখন পরীক্ষা লিখবেন যাতে LiveData টেস্টিং অন্তর্ভুক্ত থাকে, এই নিয়মটি ব্যবহার করুন!

  1. আর্কিটেকচার কম্পোনেন্টস কোর টেস্টিং লাইব্রেরির জন্য গ্রেডেল নির্ভরতা যোগ করুন (যেটিতে এই নিয়ম রয়েছে)।

app/build.gradle

testImplementation "androidx.arch.core:core-testing:$archTestingVersion"
  1. TasksViewModelTest.kt খুলুন
  2. TasksViewModelTest ক্লাসের ভিতরে InstantTaskExecutorRule যোগ করুন।

TasksViewModelTest.kt

class TasksViewModelTest {
    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()
    
    // Other code...
}

ধাপ 2. LiveDataTestUtil.kt ক্লাস যোগ করুন

আপনার পরবর্তী ধাপ হল নিশ্চিত করা যে আপনি যে LiveData পরীক্ষা করছেন তা পর্যবেক্ষণ করা হয়েছে।

আপনি যখন LiveData ব্যবহার করেন, তখন আপনার সাধারণত একটি কার্যকলাপ বা টুকরো থাকে ( LifecycleOwner ) LiveData পর্যবেক্ষণ করেন।

viewModel.resultLiveData.observe(fragment, Observer {
    // Observer code here
})

এই পর্যবেক্ষণ গুরুত্বপূর্ণ. আপনার LiveData সক্রিয় পর্যবেক্ষক প্রয়োজন

  • যেকোনো onChanged ইভেন্ট ট্রিগার করুন।
  • যেকোনো রূপান্তর ট্রিগার করুন।

আপনার ভিউ মডেলের LiveData এর জন্য প্রত্যাশিত LiveData আচরণ পেতে, আপনাকে একজন LifecycleOwner এর সাথে LiveData পর্যবেক্ষণ করতে হবে।

এটি একটি সমস্যা তৈরি করে: আপনার TasksViewModel পরীক্ষায়, আপনার LiveData পর্যবেক্ষণ করার জন্য আপনার কাছে কোনো কার্যকলাপ বা খণ্ড নেই। এটির কাছাকাছি পেতে, আপনি observeForever পদ্ধতি ব্যবহার করতে পারেন, যা নিশ্চিত করে যে LifecycleOwner মালিকের প্রয়োজন ছাড়াই LiveData ক্রমাগত পর্যবেক্ষণ করা হচ্ছে। আপনি যখন 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 নামে একটি এক্সটেনশন ফাংশন তৈরি করতে যাচ্ছেন।

  1. আপনার test উত্স সেটে LiveDataTestUtil.kt নামে একটি নতুন Kotlin ফাইল তৈরি করুন৷


  1. কপি করুন এবং নিচের কোড পেস্ট করুন.

LiveDataTestUtil.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
}

এটি একটি মোটামুটি জটিল পদ্ধতি। এটি getOrAwaitValue নামে একটি কোটলিন এক্সটেনশন ফাংশন তৈরি করে যা একজন পর্যবেক্ষককে যুক্ত করে, LiveData মান পায় এবং তারপর পর্যবেক্ষককে পরিষ্কার করে-মূলত উপরে দেখানো observeForever কোডের একটি সংক্ষিপ্ত, পুনরায় ব্যবহারযোগ্য সংস্করণ। এই ক্লাসের সম্পূর্ণ ব্যাখ্যার জন্য, এই ব্লগ পোস্টটি দেখুন

ধাপ 3. দাবী লিখতে getOrAwaitValue ব্যবহার করুন

এই ধাপে, আপনি getOrAwaitValue পদ্ধতি ব্যবহার করুন এবং একটি দাবী বিবৃতি লিখুন যা পরীক্ষা করে যে নতুন newTaskEvent ট্রিগার হয়েছে।

  1. Get the LiveData value for newTaskEvent using getOrAwaitValue .
val value = tasksViewModel.newTaskEvent.getOrAwaitValue()
  1. Assert that the value is not null.
assertThat(value.getContentIfNotHandled(), (not(nullValue())))

The complete test should look like the code below.

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()))


    }

}
  1. Run your code and watch the test pass!

Now that you've seen how to write a test, write one on your own. In this step, using the skills you've learned, practice writing another TasksViewModel test.

Step 1. Write your own ViewModel test

You'll write setFilterAllTasks_tasksAddViewVisible() . This test should check that if you've set your filter type to show all tasks, that the Add task button is visible.

  1. Using addNewTask_setsNewTaskEvent() for reference, write a test in TasksViewModelTest called setFilterAllTasks_tasksAddViewVisible() that sets the filtering mode to ALL_TASKS and asserts that the tasksAddViewVisible LiveData is true .


Use the code below to get started.

TasksViewModelTest

    @Test
    fun setFilterAllTasks_tasksAddViewVisible() {

        // Given a fresh ViewModel

        // When the filter type is ALL_TASKS

        // Then the "Add task" action is visible
        
    }

Note:

  • The TasksFilterType enum for all tasks is ALL_TASKS.
  • The visibility of the button to add a task is controlled by the LiveData tasksAddViewVisible.
  1. Run your test.

Step 2. Compare your test to the solution

Compare your solution to the solution below.

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))
    }

Check whether you do the following:

  • You create your tasksViewModel using the same AndroidX ApplicationProvider.getApplicationContext() statement.
  • You call the setFiltering method, passing in the ALL_TASKS filter type enum.
  • You check that the tasksAddViewVisible is true, using the getOrAwaitNextValue method.

Step 3. Add a @Before rule

Notice how at the start of both of your tests, you define a TasksViewModel .

TasksViewModelTest

        // Given a fresh ViewModel
        val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

When you have repeated setup code for multiple tests, you can use the @Before annotation to create a setup method and remove repeated code. Since all of these tests are going to test the TasksViewModel , and need a view model, move this code to a @Before block.

  1. Create a lateinit instance variable called tasksViewModel| .
  2. Create a method called setupViewModel .
  3. Annotate it with @Before .
  4. Move the view model instantiation code to setupViewModel .

TasksViewModelTest

    // Subject under test
    private lateinit var tasksViewModel: TasksViewModel

    @Before
    fun setupViewModel() {
        tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
    }
  1. Run your code!

সতর্কতা

Do not do the following, do not initialize the

tasksViewModel

with its definition:

val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

This will cause the same instance to be used for all tests. This is something you should avoid because each test should have a fresh instance of the subject under test (the ViewModel in this case).

Your final code for TasksViewModelTest should look like the code below.

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))
    }
    
}

Click here to see a diff between the code you started and the final code.

To download the code for the finished codelab, you can use the git command below:

$ git clone https://github.com/googlecodelabs/android-testing.git
$ cd android-testing
$ git checkout end_codelab_1


Alternatively you can download the repository as a Zip file, unzip it, and open it in Android Studio.

জিপ ডাউনলোড করুন

This codelab covered:

  • How to run tests from Android Studio.
  • The difference between local ( test ) and instrumentation tests ( androidTest ).
  • How to write local unit tests using JUnit and Hamcrest .
  • Setting up ViewModel tests with the AndroidX Test Library .

Udacity course:

অ্যান্ড্রয়েড বিকাশকারী ডকুমেন্টেশন:

Videos:

Other:

এই কোর্সে অন্যান্য কোডল্যাবগুলির লিঙ্কগুলির জন্য, কোটলিন কোডল্যাবগুলির ল্যান্ডিং পৃষ্ঠাতে উন্নত Android দেখুন৷