টেস্ট ডাবলস এবং ডিপেনডেন্সি ইনজেকশনের ভূমিকা

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

ভূমিকা

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

  • সংগ্রহস্থল ইউনিট পরীক্ষা
  • টুকরো এবং ভিউ মডেল ইন্টিগ্রেশন পরীক্ষা
  • খণ্ড নেভিগেশন পরীক্ষা

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

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

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

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

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

আপনি কি করবেন

  • একটি পরীক্ষা ডবল এবং নির্ভরতা ইনজেকশন ব্যবহার করে একটি সংগ্রহস্থলের জন্য ইউনিট পরীক্ষা লিখুন।
  • একটি পরীক্ষা ডবল এবং নির্ভরতা ইনজেকশন ব্যবহার করে একটি ভিউ মডেলের জন্য ইউনিট পরীক্ষা লিখুন।
  • Espresso UI টেস্টিং ফ্রেমওয়ার্ক ব্যবহার করে টুকরো এবং তাদের ভিউ মডেলগুলির জন্য ইন্টিগ্রেশন পরীক্ষা লিখুন।
  • Mockito এবং Espresso ব্যবহার করে নেভিগেশন পরীক্ষা লিখুন।

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

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

কোডটি ডাউনলোড করুন

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

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

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

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

নীচের নির্দেশাবলী অনুসরণ করে কোডের সাথে নিজেকে পরিচিত করতে কিছুক্ষণ সময় নিন।

ধাপ 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 পর্যবেক্ষণ করে এবং পর্দার মধ্যে প্রকৃত নেভিগেশন করে।

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

এই বিভাগে সাধারণভাবে পরীক্ষার কিছু সর্বোত্তম অনুশীলন কভার করা হয়েছে, কারণ সেগুলি Android এ প্রযোজ্য।

টেস্টিং পিরামিড

একটি পরীক্ষার কৌশল সম্পর্কে চিন্তা করার সময়, তিনটি সম্পর্কিত পরীক্ষার দিক রয়েছে:

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

এই দিকগুলির মধ্যে সহজাত ট্রেড-অফ রয়েছে। উদাহরণস্বরূপ, গতি এবং বিশ্বস্ততা একটি ট্রেড-অফ—যত দ্রুত পরীক্ষা, সাধারণত, কম বিশ্বস্ততা এবং তদ্বিপরীত। স্বয়ংক্রিয় পরীক্ষাগুলিকে এই তিনটি বিভাগে ভাগ করার একটি সাধারণ উপায় হল:

  • ইউনিট পরীক্ষা -এগুলি অত্যন্ত ফোকাসড পরীক্ষা যা একটি একক ক্লাসে চলে, সাধারণত সেই ক্লাসে একটি একক পদ্ধতি। যদি একটি ইউনিট পরীক্ষা ব্যর্থ হয়, আপনি আপনার কোডে সমস্যাটি ঠিক কোথায় তা জানতে পারবেন। বাস্তব বিশ্বে তাদের বিশ্বস্ততা কম, আপনার অ্যাপটি একটি পদ্ধতি বা শ্রেণির সম্পাদনের চেয়ে অনেক বেশি জড়িত। আপনি যখনই আপনার কোড পরিবর্তন করেন তখন তারা চালানোর জন্য যথেষ্ট দ্রুত। এগুলি প্রায়শই স্থানীয়ভাবে পরীক্ষা করা হবে ( test উত্স সেটে)। উদাহরণ: ভিউ মডেল এবং সংগ্রহস্থলে একক পদ্ধতি পরীক্ষা করা।
  • ইন্টিগ্রেশন পরীক্ষা -এগুলি একসাথে ব্যবহার করার সময় তারা প্রত্যাশা অনুযায়ী আচরণ করে তা নিশ্চিত করতে বেশ কয়েকটি ক্লাসের মিথস্ক্রিয়া পরীক্ষা করে। ইন্টিগ্রেশন টেস্ট গঠনের একটি উপায় হল তাদের একটি একক বৈশিষ্ট্য পরীক্ষা করা, যেমন একটি টাস্ক সংরক্ষণ করার ক্ষমতা। তারা ইউনিট পরীক্ষার তুলনায় কোডের একটি বৃহত্তর সুযোগ পরীক্ষা করে, কিন্তু এখনও সম্পূর্ণ বিশ্বস্ততা থাকার বিপরীতে দ্রুত চালানোর জন্য অপ্টিমাইজ করা হয়। পরিস্থিতির উপর নির্ভর করে এগুলি স্থানীয়ভাবে বা যন্ত্র পরীক্ষা হিসাবে চালানো যেতে পারে। উদাহরণ: একটি একক খণ্ডের সমস্ত কার্যকারিতা পরীক্ষা করা এবং মডেল জোড়া দেখুন।
  • এন্ড টু এন্ড টেস্ট (E2e) — একসাথে কাজ করা বৈশিষ্ট্যের সমন্বয় পরীক্ষা করুন। তারা অ্যাপের বড় অংশ পরীক্ষা করে, বাস্তব ব্যবহার ঘনিষ্ঠভাবে অনুকরণ করে এবং তাই সাধারণত ধীর হয়। তাদের সর্বোচ্চ বিশ্বস্ততা রয়েছে এবং আপনাকে বলে যে আপনার আবেদনটি আসলে সামগ্রিকভাবে কাজ করে। সর্বোপরি, এই পরীক্ষাগুলি হবে যন্ত্রযুক্ত পরীক্ষা ( androidTest উত্স সেটে)
    উদাহরণ: পুরো অ্যাপটি শুরু করা এবং কয়েকটি বৈশিষ্ট্য একসাথে পরীক্ষা করা।

এই পরীক্ষাগুলির প্রস্তাবিত অনুপাত প্রায়শই একটি পিরামিড দ্বারা প্রতিনিধিত্ব করা হয়, যার বেশিরভাগ পরীক্ষাই ইউনিট পরীক্ষা।

আর্কিটেকচার এবং টেস্টিং

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

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



এই পাঠে, আপনি দেখতে পাবেন কীভাবে উপরের আর্কিটেকচারের অংশগুলি সঠিকভাবে বিচ্ছিন্নভাবে পরীক্ষা করা যায়:

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

শেষ থেকে শেষ পরীক্ষা পরবর্তী পাঠে কভার করা হবে।

আপনি যখন একটি ক্লাসের একটি অংশের জন্য একটি ইউনিট পরীক্ষা লেখেন (একটি পদ্ধতি বা পদ্ধতির একটি ছোট সংগ্রহ), আপনার লক্ষ্য শুধুমাত্র সেই ক্লাসের কোডটি পরীক্ষা করা

একটি নির্দিষ্ট ক্লাস বা ক্লাসে শুধুমাত্র কোড পরীক্ষা করা কঠিন হতে পারে। এর একটি উদাহরণ তাকান. main উৎস সেটে data.source.DefaultTaskRepository ক্লাস খুলুন। এটি অ্যাপের সংগ্রহস্থল, এবং এটি সেই ক্লাস যা আপনি পরবর্তী ইউনিট পরীক্ষা লিখবেন।

আপনার লক্ষ্য হল সেই ক্লাসে শুধুমাত্র কোড পরীক্ষা করা। তবুও, DefaultTaskRepository অন্যান্য ক্লাসের উপর নির্ভর করে, যেমন LocalTaskDataSource এবং RemoteTaskDataSource কাজ করার জন্য। এটি বলার আরেকটি উপায় হল LocalTaskDataSource এবং RemoteTaskDataSource হল DefaultTaskRepository এর নির্ভরতা

তাই DefaultTaskRepository এর প্রতিটি মেথড ডেটা সোর্স ক্লাসে মেথড কল করে, যা অন্য ক্লাসে কল মেথডকে ডাটাবেসে তথ্য সংরক্ষণ করতে বা নেটওয়ার্কের সাথে যোগাযোগ করে।



উদাহরণস্বরূপ, DefaultTasksRepo তে এই পদ্ধতিটি দেখুন।

    suspend fun getTasks(forceUpdate: Boolean = false): Result<List<Task>> {
        if (forceUpdate) {
            try {
                updateTasksFromRemoteDataSource()
            } catch (ex: Exception) {
                return Result.Error(ex)
            }
        }
        return tasksLocalDataSource.getTasks()
    }

getTasks হল সবচেয়ে "বেসিক" কলগুলির মধ্যে একটি যা আপনি আপনার সংগ্রহস্থলে করতে পারেন। এই পদ্ধতিতে একটি SQLite ডাটাবেস থেকে পড়া এবং নেটওয়ার্ক কল করা (আপডেট করার জন্য কল updateTasksFromRemoteDataSource ) অন্তর্ভুক্ত রয়েছে। এটি শুধুমাত্র সংগ্রহস্থল কোডের চেয়ে অনেক বেশি কোড জড়িত।

এখানে আরও কিছু নির্দিষ্ট কারণ রয়েছে কেন সংগ্রহস্থল পরীক্ষা করা কঠিন:

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

টেস্ট ডাবলস

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

এখানে কিছু ধরণের টেস্ট ডাবল রয়েছে:

জাল

একটি টেস্ট ডাবল যার ক্লাসের একটি "কাজ" বাস্তবায়ন রয়েছে, কিন্তু এটি এমনভাবে প্রয়োগ করা হয়েছে যা এটিকে পরীক্ষার জন্য ভাল করে তোলে কিন্তু উৎপাদনের জন্য অনুপযুক্ত।

উপহাস

একটি টেস্ট ডবল যা ট্র্যাক করে তার কোন পদ্ধতিগুলিকে বলা হয়েছিল৷ তারপরে এটির পদ্ধতিগুলি সঠিকভাবে বলা হয়েছিল কিনা তার উপর নির্ভর করে এটি একটি পরীক্ষা পাস করে বা ব্যর্থ হয়।

স্টাব

একটি পরীক্ষা দ্বিগুণ যাতে কোন যুক্তি নেই এবং শুধুমাত্র আপনি যা প্রোগ্রাম করেন তা ফেরত দেয়। একটি StubTaskRepository উদাহরন স্বরূপ getTasks থেকে নির্দিষ্ট কিছু কাজের সমন্বয় ফেরানোর জন্য প্রোগ্রাম করা যেতে পারে।

ডামি

একটি পরীক্ষা দ্বিগুণ যা চারপাশে পাস করা হয় কিন্তু ব্যবহার করা হয় না, যেমন আপনাকে শুধুমাত্র একটি প্যারামিটার হিসাবে এটি প্রদান করতে হবে। আপনার যদি একটি NoOpTaskRepository থাকে, তবে এটি কোনো পদ্ধতিতে কোনো কোড ছাড়াই TaskRepository বাস্তবায়ন করবে।

গুপ্তচর

একটি টেস্ট ডবল যা কিছু অতিরিক্ত তথ্যের ট্র্যাক রাখে; উদাহরণস্বরূপ, আপনি যদি একটি SpyTaskRepository তৈরি করেন, তাহলে এটি addTask পদ্ধতিটি কতবার কল করা হয়েছে তার ট্র্যাক রাখতে পারে।

টেস্ট ডাবল সম্পর্কে আরও তথ্যের জন্য, টয়লেটে টেস্টিং দেখুন: আপনার টেস্ট ডাবলস জানুন

অ্যান্ড্রয়েডে ব্যবহৃত সবচেয়ে সাধারণ টেস্ট ডাবল হল ফেকস এবং মকস

এই টাস্কে, আপনি একটি FakeDataSource টেস্ট তৈরি করতে যাচ্ছেন যা ইউনিট টেস্ট DefaultTasksRepository প্রকৃত ডেটা উৎস থেকে ডিকপল করা হয়েছে।

ধাপ 1: FakeDataSource ক্লাস তৈরি করুন

এই ধাপে আপনি FakeDataSouce নামক একটি ক্লাস তৈরি করতে যাচ্ছেন, যা একটি LocalDataSource এবং RemoteDataSource এর দ্বিগুণ পরীক্ষা হবে।

  1. পরীক্ষার উৎস সেটে, নতুন -> প্যাকেজ নির্বাচন করুন ডান ক্লিক করুন।

  1. ভিতরে একটি উৎস প্যাকেজ সহ একটি ডেটা প্যাকেজ তৈরি করুন।
  2. ডেটা/সোর্স প্যাকেজে FakeDataSource নামে একটি নতুন ক্লাস তৈরি করুন।

ধাপ 2: TasksDataSource ইন্টারফেস বাস্তবায়ন করুন

আপনার নতুন ক্লাস FakeDataSource একটি টেস্ট ডাবল হিসাবে ব্যবহার করতে সক্ষম হতে, এটি অবশ্যই অন্যান্য ডেটা উত্সগুলি প্রতিস্থাপন করতে সক্ষম হবে। এই ডেটা উত্সগুলি হল TasksLocalDataSource এবং TasksRemoteDataSource

  1. লক্ষ্য করুন কিভাবে এই দুটিই TasksDataSource ইন্টারফেস বাস্তবায়ন করে।
class TasksLocalDataSource internal constructor(
    private val tasksDao: TasksDao,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : TasksDataSource { ... }

object TasksRemoteDataSource : TasksDataSource { ... }
  1. FakeDataSource কার্যকর করুন TasksDataSource :
class FakeDataSource : TasksDataSource {

}

অ্যান্ড্রয়েড স্টুডিও অভিযোগ করবে যে আপনি TasksDataSource জন্য প্রয়োজনীয় পদ্ধতি প্রয়োগ করেননি।

  1. দ্রুত-সমাধান মেনু ব্যবহার করুন এবং সদস্যদের বাস্তবায়ন নির্বাচন করুন।


  1. সমস্ত পদ্ধতি নির্বাচন করুন এবং ঠিক আছে টিপুন।

ধাপ 3: FakeDataSource এ getTasks পদ্ধতি প্রয়োগ করুন

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

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

একটি FakeDataSource

  • আপনি একটি বাস্তব ডাটাবেস বা নেটওয়ার্কের উপর নির্ভর করার প্রয়োজন ছাড়াই DefaultTasksRepository এ কোড পরীক্ষা করতে দেয়।
  • পরীক্ষার জন্য একটি "বাস্তব-পর্যাপ্ত" বাস্তবায়ন প্রদান করে।
  1. FakeDataSource কন্সট্রাক্টর পরিবর্তন করে একটি var তৈরি করতে হবে যার নাম tasks যা একটি MutableList<Task>? একটি খালি পরিবর্তনযোগ্য তালিকার একটি ডিফল্ট মান সহ।
class FakeDataSource(var tasks: MutableList<Task>? = mutableListOf()) : TasksDataSource { // Rest of class }


এটি একটি ডাটাবেস বা সার্ভার প্রতিক্রিয়া হিসাবে "জাল" কাজের তালিকা। আপাতত, লক্ষ্য হল সংগ্রহস্থলের getTasks পদ্ধতি পরীক্ষা করা। এটি ডেটা উত্সের getTasks , deleteAllTasks এবং saveTask পদ্ধতিগুলিকে কল করে৷

এই পদ্ধতিগুলির একটি জাল সংস্করণ লিখুন:

  1. getTasks লিখুন : যদি tasks null না হয়, একটি Success ফলাফল ফেরত দিন। যদি tasks null হয়, একটি Error ফলাফল ফেরত দিন।
  2. deleteAllTasks লিখুন: পরিবর্তনযোগ্য কাজের তালিকা সাফ করুন।
  3. saveTask লিখুন: তালিকায় টাস্ক যোগ করুন।

এই পদ্ধতিগুলি, FakeDataSource জন্য প্রয়োগ করা হয়েছে, নীচের কোডের মতো দেখতে৷

override suspend fun getTasks(): Result<List<Task>> {
    tasks?.let { return Success(ArrayList(it)) }
    return Error(
        Exception("Tasks not found")
    )
}


override suspend fun deleteAllTasks() {
    tasks?.clear()
}

override suspend fun saveTask(task: Task) {
    tasks?.add(task)
}

প্রয়োজন হলে এখানে আমদানি বিবৃতি আছে:

import com.example.android.architecture.blueprints.todoapp.data.Result
import com.example.android.architecture.blueprints.todoapp.data.Result.Error
import com.example.android.architecture.blueprints.todoapp.data.Result.Success
import com.example.android.architecture.blueprints.todoapp.data.Task

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

এই ধাপে, আপনি ম্যানুয়াল ডিপেন্ডেন্সি ইনজেকশন নামক একটি কৌশল ব্যবহার করতে যাচ্ছেন যাতে আপনি এইমাত্র তৈরি করা জাল পরীক্ষা দ্বিগুণ ব্যবহার করতে পারেন।

প্রধান সমস্যা হল যে আপনার কাছে একটি FakeDataSource আছে, কিন্তু আপনি কীভাবে পরীক্ষায় এটি ব্যবহার করবেন তা স্পষ্ট নয়। এটি TasksRemoteDataSource এবং TasksLocalDataSource প্রতিস্থাপন করতে হবে, কিন্তু শুধুমাত্র পরীক্ষায়। TasksRemoteDataSource এবং TasksLocalDataSource উভয়ই DefaultTasksRepository এর নির্ভরতা, যার অর্থ এই ক্লাসগুলি চালানোর জন্য DefaultTasksRepositories প্রয়োজন বা "নির্ভর করে"।

এই মুহূর্তে, DefaultTasksRepository এর init পদ্ধতির মধ্যে নির্ভরতাগুলি তৈরি করা হয়েছে।

DefaultTasksRepository.kt

class DefaultTasksRepository private constructor(application: Application) {

    private val tasksRemoteDataSource: TasksDataSource
    private val tasksLocalDataSource: TasksDataSource

   // Some other code

    init {
        val database = Room.databaseBuilder(application.applicationContext,
            ToDoDatabase::class.java, "Tasks.db")
            .build()

        tasksRemoteDataSource = TasksRemoteDataSource
        tasksLocalDataSource = TasksLocalDataSource(database.taskDao())
    }
    // Rest of class
}

যেহেতু আপনি DefaultTasksRepository ভিতরে taskLocalDataSource এবং tasksRemoteDataSource তৈরি এবং বরাদ্দ করছেন, সেগুলি মূলত হার্ড কোডেড। আপনার টেস্ট ডাবলে অদলবদল করার কোন উপায় নেই।

আপনি এর পরিবর্তে যা করতে চান তা হল এই ডেটা উত্সগুলিকে হার্ড-কোডিংয়ের পরিবর্তে ক্লাসে সরবরাহ করা । নির্ভরতা প্রদান করা নির্ভরতা ইনজেকশন হিসাবে পরিচিত। নির্ভরতা প্রদানের বিভিন্ন উপায় রয়েছে এবং তাই বিভিন্ন ধরনের নির্ভরতা ইনজেকশন রয়েছে।

কনস্ট্রাক্টর ডিপেনডেন্সি ইনজেকশন আপনাকে কনস্ট্রাক্টরে পাস করে টেস্ট ডবলে অদলবদল করতে দেয়।

ইনজেকশন নেই

ইনজেকশন

ধাপ 1: DefaultTasksRepository-এ কনস্ট্রাক্টর ডিপেন্ডেন্সি ইনজেকশন ব্যবহার করুন

  1. DefaultTaskRepository এর কনস্ট্রাক্টরকে একটি Application নেওয়া থেকে ডেটা উত্স এবং coroutine ডিসপ্যাচার উভয়ই গ্রহণ করতে পরিবর্তন করুন (যা আপনাকে আপনার পরীক্ষার জন্য অদলবদল করতে হবে - এটি coroutines-এর তৃতীয় পাঠ বিভাগে আরও বিশদে বর্ণনা করা হয়েছে)।

DefaultTasksRepository.kt

// REPLACE
class DefaultTasksRepository private constructor(application: Application) { // Rest of class }

// WITH

class DefaultTasksRepository(
    private val tasksRemoteDataSource: TasksDataSource,
    private val tasksLocalDataSource: TasksDataSource,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO) { // Rest of class }
  1. যেহেতু আপনি নির্ভরতা পাস করেছেন, init পদ্ধতিটি সরান। আপনাকে আর নির্ভরতা তৈরি করতে হবে না।
  2. এছাড়াও পুরানো উদাহরণ ভেরিয়েবল মুছে দিন। আপনি কনস্ট্রাক্টরে তাদের সংজ্ঞায়িত করছেন:

DefaultTasksRepository.kt

// Delete these old variables
private val tasksRemoteDataSource: TasksDataSource
private val tasksLocalDataSource: TasksDataSource
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
  1. অবশেষে, নতুন কনস্ট্রাক্টর ব্যবহার করতে getRepository পদ্ধতি আপডেট করুন:

DefaultTasksRepository.kt

    companion object {
        @Volatile
        private var INSTANCE: DefaultTasksRepository? = null

        fun getRepository(app: Application): DefaultTasksRepository {
            return INSTANCE ?: synchronized(this) {
                val database = Room.databaseBuilder(app,
                    ToDoDatabase::class.java, "Tasks.db")
                    .build()
                DefaultTasksRepository(TasksRemoteDataSource, TasksLocalDataSource(database.taskDao())).also {
                    INSTANCE = it
                }
            }
        }
    }

আপনি এখন কনস্ট্রাক্টর নির্ভরতা ইনজেকশন ব্যবহার করছেন!

ধাপ 2: আপনার পরীক্ষায় আপনার FakeDataSource ব্যবহার করুন

এখন আপনার কোড কনস্ট্রাক্টর নির্ভরতা ইনজেকশন ব্যবহার করছে, আপনি আপনার DefaultTasksRepository পরীক্ষা করতে আপনার জাল ডেটা উৎস ব্যবহার করতে পারেন।

  1. DefaultTasksRepository ক্লাসের নামের উপর ডান-ক্লিক করুন এবং জেনারেট নির্বাচন করুন, তারপর পরীক্ষা করুন।
  2. পরীক্ষার উৎস সেটে DefaultTasksRepositoryTest তৈরি করতে প্রম্পটগুলি অনুসরণ করুন।
  3. আপনার নতুন DefaultTasksRepositoryTest ক্লাসের শীর্ষে, আপনার জাল ডেটা উত্সগুলিতে ডেটা উপস্থাপন করতে নীচে সদস্য ভেরিয়েবলগুলি যুক্ত করুন৷

DefaultTasksRepositoryTest.kt

    private val task1 = Task("Title1", "Description1")
    private val task2 = Task("Title2", "Description2")
    private val task3 = Task("Title3", "Description3")
    private val remoteTasks = listOf(task1, task2).sortedBy { it.id }
    private val localTasks = listOf(task3).sortedBy { it.id }
    private val newTasks = listOf(task3).sortedBy { it.id }
  1. তিনটি ভেরিয়েবল তৈরি করুন, দুটি FakeDataSource সদস্য ভেরিয়েবল (আপনার সংগ্রহস্থলের জন্য প্রতিটি ডেটা উৎসের জন্য একটি) এবং DefaultTasksRepository জন্য একটি পরিবর্তনশীল যা আপনি পরীক্ষা করবেন।

DefaultTasksRepositoryTest.kt

    private lateinit var tasksRemoteDataSource: FakeDataSource
    private lateinit var tasksLocalDataSource: FakeDataSource

    // Class under test
    private lateinit var tasksRepository: DefaultTasksRepository

একটি পরীক্ষাযোগ্য DefaultTasksRepository সেট আপ এবং আরম্ভ করার জন্য একটি পদ্ধতি তৈরি করুন। এই DefaultTasksRepository আপনার টেস্ট ডবল, FakeDataSource ব্যবহার করবে।

  1. createRepository নামে একটি পদ্ধতি তৈরি করুন এবং @Before দিয়ে এটি টীকা করুন।
  2. remoteTasks এবং localTasks লিস্ট ব্যবহার করে আপনার জাল ডেটা সোর্স ইনস্ট্যান্টিয়েট করুন।
  3. আপনার তৈরি করা দুটি জাল ডেটা উত্স এবং Dispatchers.Unconfined ব্যবহার করে আপনার tasksRepository ইনস্ট্যান্ট করুন৷ আনসীমান্ত৷

চূড়ান্ত পদ্ধতিটি নীচের কোডের মতো হওয়া উচিত।

DefaultTasksRepositoryTest.kt

    @Before
    fun createRepository() {
        tasksRemoteDataSource = FakeDataSource(remoteTasks.toMutableList())
        tasksLocalDataSource = FakeDataSource(localTasks.toMutableList())
        // Get a reference to the class under test
        tasksRepository = DefaultTasksRepository(
            // TODO Dispatchers.Unconfined should be replaced with Dispatchers.Main
            //  this requires understanding more about coroutines + testing
            //  so we will keep this as Unconfined for now.
            tasksRemoteDataSource, tasksLocalDataSource, Dispatchers.Unconfined
        )
    }

ধাপ 3: DefaultTasksRepository getTasks() টেস্ট লিখুন

একটি DefaultTasksRepository পরীক্ষা লেখার সময়!

  1. সংগ্রহস্থলের getTasks পদ্ধতির জন্য একটি পরীক্ষা লিখুন। আপনি যখন getTasks true দিয়ে কল করেন (অর্থাৎ এটি দূরবর্তী ডেটা উৎস থেকে পুনরায় লোড করা উচিত) তখন পরীক্ষা করুন যে এটি দূরবর্তী ডেটা উত্স থেকে ডেটা ফেরত দেয় (স্থানীয় ডেটা উত্সের বিপরীতে)।

DefaultTasksRepositoryTest.kt

@Test
    fun getTasks_requestsAllTasksFromRemoteDataSource(){
        // When tasks are requested from the tasks repository
        val tasks = tasksRepository.getTasks(true) as Success

        // Then tasks are loaded from the remote data source
        assertThat(tasks.data, IsEqual(remoteTasks))
    }

আপনি getTasks কল করলে আপনি একটি ত্রুটি পাবেন getTasks:

ধাপ 4: রানব্লকিং টেস্ট যোগ করুন

coroutine ত্রুটি প্রত্যাশিত কারণ getTasks হল একটি suspend ফাংশন এবং এটিকে কল করার জন্য আপনাকে একটি coroutine চালু করতে হবে৷ এর জন্য, আপনার একটি করুটিন সুযোগ প্রয়োজন। এই ত্রুটিটি সমাধান করার জন্য, আপনার পরীক্ষায় লঞ্চিং কোরোটিনগুলি পরিচালনা করার জন্য আপনাকে কিছু গ্রেডেল নির্ভরতা যুক্ত করতে হবে।

  1. testImplementation ব্যবহার করে সেট করা পরীক্ষার উৎসে কোরোটিন পরীক্ষার জন্য প্রয়োজনীয় নির্ভরতা যোগ করুন।

app/build.gradle

testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"

সিঙ্ক করতে ভুলবেন না!

kotlinx-coroutines-test হল coroutines টেস্ট লাইব্রেরি, বিশেষ করে coroutines পরীক্ষা করার জন্য। আপনার পরীক্ষা চালানোর জন্য, runBlockingTest ফাংশনটি ব্যবহার করুন। এটি coroutines টেস্ট লাইব্রেরি দ্বারা প্রদত্ত একটি ফাংশন। এটি কোডের একটি ব্লক নেয় এবং তারপরে কোডের এই ব্লকটিকে একটি বিশেষ কোরাউটিন প্রসঙ্গে চালায় যা সিঙ্ক্রোনাসভাবে এবং অবিলম্বে চলে, যার অর্থ ক্রিয়াগুলি একটি নির্ধারক ক্রমে ঘটবে। এটি মূলত আপনার কোরোটিনগুলিকে নন-করোটিনের মতো চালায়, তাই এটি কোড পরীক্ষার জন্য বোঝানো হয়েছে।

আপনি যখন একটি suspend ফাংশন কল করছেন তখন আপনার পরীক্ষার ক্লাসে runBlockingTest ব্যবহার করুন। runBlockingTest কীভাবে কাজ করে এবং এই সিরিজের পরবর্তী কোডল্যাবে কীভাবে কোরোটিন পরীক্ষা করা যায় সে সম্পর্কে আপনি আরও শিখবেন।

  1. ক্লাসের উপরে @ExperimentalCoroutinesApi যোগ করুন। এটি প্রকাশ করে যে আপনি জানেন যে আপনি ক্লাসে একটি পরীক্ষামূলক coroutine api ( runBlockingTest ) ব্যবহার করছেন। এটি ছাড়া, আপনি একটি সতর্কতা পাবেন।
  2. আপনার DefaultTasksRepositoryTest এ ফিরে আসুন, runBlockingTest যোগ করুন যাতে এটি আপনার পুরো পরীক্ষায় কোডের "ব্লক" হিসেবে নেয়।

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

DefaultTasksRepositoryTest.kt

import com.example.android.architecture.blueprints.todoapp.data.Result.Success
import com.example.android.architecture.blueprints.todoapp.data.Task
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import org.hamcrest.core.IsEqual
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test


@ExperimentalCoroutinesApi
class DefaultTasksRepositoryTest {

    private val task1 = Task("Title1", "Description1")
    private val task2 = Task("Title2", "Description2")
    private val task3 = Task("Title3", "Description3")
    private val remoteTasks = listOf(task1, task2).sortedBy { it.id }
    private val localTasks = listOf(task3).sortedBy { it.id }
    private val newTasks = listOf(task3).sortedBy { it.id }

    private lateinit var tasksRemoteDataSource: FakeDataSource
    private lateinit var tasksLocalDataSource: FakeDataSource

    // Class under test
    private lateinit var tasksRepository: DefaultTasksRepository

    @Before
    fun createRepository() {
        tasksRemoteDataSource = FakeDataSource(remoteTasks.toMutableList())
        tasksLocalDataSource = FakeDataSource(localTasks.toMutableList())
        // Get a reference to the class under test
        tasksRepository = DefaultTasksRepository(
            // TODO Dispatchers.Unconfined should be replaced with Dispatchers.Main
            //  this requires understanding more about coroutines + testing
            //  so we will keep this as Unconfined for now.
            tasksRemoteDataSource, tasksLocalDataSource, Dispatchers.Unconfined
        )
    }

    @Test
    fun getTasks_requestsAllTasksFromRemoteDataSource() = runBlockingTest {
        // When tasks are requested from the tasks repository
        val tasks = tasksRepository.getTasks(true) as Success

        // Then tasks are loaded from the remote data source
        assertThat(tasks.data, IsEqual(remoteTasks))
    }

}
  1. আপনার নতুন getTasks_requestsAllTasksFromRemoteDataSource পরীক্ষা চালান এবং নিশ্চিত করুন যে এটি কাজ করে এবং ত্রুটি চলে গেছে!

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

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

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

এই টাস্কে, আপনি মডেলগুলি দেখার জন্য নির্ভরতা ইনজেকশন প্রয়োগ করেন।

ধাপ 1. একটি TasksRepository ইন্টারফেস তৈরি করুন

কনস্ট্রাক্টর নির্ভরতা ইনজেকশন ব্যবহার করার প্রথম ধাপ হল জাল এবং আসল ক্লাসের মধ্যে ভাগ করা একটি সাধারণ ইন্টারফেস তৈরি করা।

এই অনুশীলনে কিভাবে দেখায়? TasksRemoteDataSource , TasksLocalDataSource এবং FakeDataSource দেখুন এবং লক্ষ্য করুন যে তারা সবাই একই ইন্টারফেস ভাগ করে: TasksDataSource । এটি আপনাকে DefaultTasksRepository এর কনস্ট্রাক্টরে বলতে দেয় যা আপনি একটি TasksDataSource এ নেন।

DefaultTasksRepository.kt

class DefaultTasksRepository(
   private val tasksRemoteDataSource: TasksDataSource,
   private val tasksLocalDataSource: TasksDataSource,
   private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO) {

এটিই আমাদেরকে আপনার FakeDataSource অদলবদল করতে দেয়!

এরপরে, DefaultTasksRepository জন্য একটি ইন্টারফেস তৈরি করুন, যেমন আপনি ডেটা উত্সের জন্য করেছিলেন। এটি DefaultTasksRepository এর সমস্ত পাবলিক পদ্ধতি (পাবলিক API পৃষ্ঠ) অন্তর্ভুক্ত করতে হবে।

  1. DefaultTasksRepository খুলুন এবং ক্লাসের নামের উপর ডান-ক্লিক করুন । তারপর রিফ্যাক্টর -> এক্সট্রাক্ট -> ইন্টারফেস নির্বাচন করুন।

  1. আলাদা ফাইল করার জন্য এক্সট্রাক্ট নির্বাচন করুন।

  1. এক্সট্র্যাক্ট ইন্টারফেস উইন্ডোতে, ইন্টারফেসের নামটি TasksRepository এ পরিবর্তন করুন।
  2. মেম্বারস টু ফর্ম ইন্টারফেস বিভাগে, দুই সহচর সদস্য এবং ব্যক্তিগত পদ্ধতি ব্যতীত সমস্ত সদস্য পরীক্ষা করুন।


  1. রিফ্যাক্টরে ক্লিক করুন। নতুন TasksRepository ইন্টারফেস ডেটা/সোর্স প্যাকেজে উপস্থিত হওয়া উচিত।

এবং DefaultTasksRepository এখন TasksRepository প্রয়োগ করে।

  1. সবকিছু এখনও কার্যকরী ক্রমে আছে তা নিশ্চিত করতে আপনার অ্যাপটি চালান (পরীক্ষা নয়)।

ধাপ 2. FakeTestRepository তৈরি করুন

এখন আপনার ইন্টারফেস আছে, আপনি DefaultTaskRepository টেস্ট ডবল তৈরি করতে পারেন।

  1. টেস্ট সোর্স সেটে, ডেটা/সোর্সে Kotlin ফাইল তৈরি করুন এবং FakeTestRepository.kt ক্লাস করুন এবং TasksRepository ইন্টারফেস থেকে প্রসারিত করুন।

FakeTestRepository.kt

class FakeTestRepository : TasksRepository  {
}

আপনাকে বলা হবে যে আপনাকে ইন্টারফেস পদ্ধতিগুলি বাস্তবায়ন করতে হবে।

  1. যতক্ষণ না আপনি পরামর্শ মেনুটি দেখতে পাচ্ছেন ততক্ষণ ত্রুটিটির উপরে হোভার করুন, তারপরে ক্লিক করুন এবং সদস্য প্রয়োগ করুন নির্বাচন করুন।
  1. সমস্ত পদ্ধতি নির্বাচন করুন এবং ঠিক আছে টিপুন।

ধাপ 3. FakeTestRepository পদ্ধতি প্রয়োগ করুন

আপনার কাছে এখন "বাস্তবায়িত নয়" পদ্ধতি সহ একটি FakeTestRepository ক্লাস রয়েছে। আপনি যেভাবে FakeDataSource প্রয়োগ করেছেন তার অনুরূপ, FakeTestRepository স্থানীয় এবং দূরবর্তী ডেটা উত্সগুলির মধ্যে একটি জটিল মধ্যস্থতার সাথে মোকাবিলা করার পরিবর্তে একটি ডেটা কাঠামো দ্বারা সমর্থন করা হবে৷

মনে রাখবেন যে আপনার FakeTestRepository FakeDataSource s বা এরকম কিছু ব্যবহার করার দরকার নেই; এটি শুধুমাত্র প্রদত্ত ইনপুট বাস্তবসম্মত জাল আউটপুট ফেরত প্রয়োজন. আপনি কাজের তালিকা সংরক্ষণ করতে একটি LinkedHashMap এবং আপনার পর্যবেক্ষণযোগ্য কাজের জন্য একটি MutableLiveData ব্যবহার করবেন।

  1. FakeTestRepository এ, একটি LinkedHashMap ভেরিয়েবল যোগ করুন যা বর্তমান কাজের তালিকা এবং আপনার পর্যবেক্ষণযোগ্য কাজের জন্য একটি MutableLiveData উপস্থাপন করে।

FakeTestRepository.kt

class FakeTestRepository : TasksRepository {

    var tasksServiceData: LinkedHashMap<String, Task> = LinkedHashMap()

    private val observableTasks = MutableLiveData<Result<List<Task>>>()


    // Rest of class
}

নিম্নলিখিত পদ্ধতিগুলি প্রয়োগ করুন:

  1. getTasks — এই পদ্ধতিটি tasksServiceData নিতে হবে এবং এটিকে tasksServiceData.values.toList() ব্যবহার করে একটি তালিকায় পরিণত করতে হবে এবং তারপর এটিকে Success ফলাফল হিসাবে ফিরিয়ে দিতে হবে।
  2. refreshTasksgetTasks() দ্বারা যা ফেরত দেওয়া হয় তা হতে observableTasks টাস্কের মান আপডেট করে।
  3. observeTasksrunBlocking ব্যবহার করে একটি coroutine তৈরি করে এবং refreshTasks চালায়, তারপর observableTasks ফেরত দেয়।

নীচে সেই পদ্ধতিগুলির জন্য কোড রয়েছে।

FakeTestRepository.kt

class FakeTestRepository : TasksRepository {

    var tasksServiceData: LinkedHashMap<String, Task> = LinkedHashMap()

    private val observableTasks = MutableLiveData<Result<List<Task>>>()

    override suspend fun getTasks(forceUpdate: Boolean): Result<List<Task>> {
        return Result.Success(tasksServiceData.values.toList())
    }

    override suspend fun refreshTasks() {
        observableTasks.value = getTasks()
    }

    override fun observeTasks(): LiveData<Result<List<Task>>> {
        runBlocking { refreshTasks() }
        return observableTasks
    }

    // Rest of class

}

ধাপ 4. অ্যাড টাস্কে পরীক্ষার জন্য একটি পদ্ধতি যোগ করুন

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

  1. addTasks মেথড যোগ করুন, যা vararg টাস্ক নেয়, প্রত্যেকটিকে HashMap এ যোগ করে, এবং তারপর কাজগুলো রিফ্রেশ করে।

FakeTestRepository.kt

    fun addTasks(vararg tasks: Task) {
        for (task in tasks) {
            tasksServiceData[task.id] = task
        }
        runBlocking { refreshTasks() }
    }

এই মুহুর্তে আপনার কাছে বাস্তবায়িত কয়েকটি মূল পদ্ধতির সাথে পরীক্ষার জন্য একটি জাল সংগ্রহস্থল রয়েছে। পরবর্তী, আপনার পরীক্ষায় এটি ব্যবহার করুন!

এই টাস্কে আপনি একটি ViewModel এর ভিতরে একটি জাল ক্লাস ব্যবহার করেন। TasksViewModel এর কনস্ট্রাক্টরে একটি TasksRepository ভেরিয়েবল যোগ করে কন্সট্রাক্টর নির্ভরতা ইনজেকশনের মাধ্যমে দুটি ডেটা উত্স গ্রহণ করতে কনস্ট্রাক্টর নির্ভরতা ইনজেকশন ব্যবহার করুন।

ভিউ মডেলগুলির সাথে এই প্রক্রিয়াটি একটু ভিন্ন কারণ আপনি সেগুলি সরাসরি নির্মাণ করেন না। যেমন:

class TasksFragment : Fragment() {

    private val viewModel by viewModels<TasksViewModel>()
    
    // Rest of class...

}


উপরের কোডের মতো, আপনি viewModel's সম্পত্তি প্রতিনিধি ব্যবহার করছেন যা ভিউ মডেল তৈরি করে। ভিউ মডেলটি কীভাবে তৈরি করা হয় তা পরিবর্তন করতে, আপনাকে একটি ViewModelProvider.Factory যোগ করতে হবে এবং ব্যবহার করতে হবে। আপনি যদি ViewModelProvider.Factory সাথে পরিচিত না হন তবে আপনি এখানে এটি সম্পর্কে আরও জানতে পারেন।

ধাপ 1. TasksViewModel-এ একটি ViewModelFactory তৈরি করুন এবং ব্যবহার করুন

আপনি Tasks স্ক্রিনের সাথে সম্পর্কিত ক্লাস এবং পরীক্ষা আপডেট করে শুরু করুন।

  1. TasksViewModel খুলুন
  2. TasksViewModel এর কন্সট্রাক্টর পরিবর্তন করে TasksRepository এ ক্লাশের ভিতরে তৈরি না করে তা নিতে পারেন।

TasksViewModel.kt

// REPLACE
class TasksViewModel(application: Application) : AndroidViewModel(application) {

    private val tasksRepository = DefaultTasksRepository.getRepository(application)

    // Rest of class
}

// WITH

class TasksViewModel( private val tasksRepository: TasksRepository ) : ViewModel() { 
    // Rest of class 
}

যেহেতু আপনি কনস্ট্রাক্টর পরিবর্তন করেছেন, তাই আপনাকে এখন TasksViewModel তৈরি করতে একটি কারখানা ব্যবহার করতে হবে। TasksViewModel এর মতো একই ফাইলে ফ্যাক্টরি ক্লাস রাখুন, তবে আপনি এটির নিজস্ব ফাইলেও রাখতে পারেন।

  1. TasksViewModel ফাইলের নীচে, ক্লাসের বাইরে, একটি TasksViewModelFactory যোগ করুন যা একটি সাধারণ TasksRepository এ নেয়।

TasksViewModel.kt

@Suppress("UNCHECKED_CAST")
class TasksViewModelFactory (
    private val tasksRepository: TasksRepository
) : ViewModelProvider.NewInstanceFactory() {
    override fun <T : ViewModel> create(modelClass: Class<T>) =
        (TasksViewModel(tasksRepository) as T)
}


ViewModel কীভাবে তৈরি করা হয় তা আপনি পরিবর্তন করার আদর্শ উপায়। এখন যেহেতু আপনার কারখানা আছে, আপনি যেখানেই আপনার ভিউ মডেল তৈরি করেন সেখানেই এটি ব্যবহার করুন।

  1. ফ্যাক্টরি ব্যবহার করতে TasksFragment আপডেট করুন।

TasksFragment.kt

// REPLACE
private val viewModel by viewModels<TasksViewModel>()

// WITH

private val viewModel by viewModels<TasksViewModel> {
    TasksViewModelFactory(DefaultTasksRepository.getRepository(requireActivity().application))
}
  1. আপনার অ্যাপ কোড চালান এবং নিশ্চিত করুন যে সবকিছু এখনও কাজ করছে!

ধাপ 2. TasksViewModelTest-এর ভিতরে FakeTestRepository ব্যবহার করুন

এখন আপনার ভিউ মডেল পরীক্ষায় আসল সংগ্রহস্থল ব্যবহার করার পরিবর্তে, আপনি জাল সংগ্রহস্থল ব্যবহার করতে পারেন।

  1. TasksViewModelTest খুলুন
  2. TasksViewModelTest এ একটি FakeTestRepository সম্পত্তি যোগ করুন।

TaskViewModelTest.kt

@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {

    // Use a fake repository to be injected into the viewmodel
    private lateinit var tasksRepository: FakeTestRepository
    
    // Rest of class
}
  1. তিনটি কাজ সহ একটি FakeTestRepository তৈরি করতে setupViewModel পদ্ধতিটি আপডেট করুন এবং তারপর এই সংগ্রহস্থলের সাথে tasksViewModel তৈরি করুন।

TasksViewModelTest.kt

    @Before
    fun setupViewModel() {
        // We initialise the tasks to 3, with one active and two completed
        tasksRepository = FakeTestRepository()
        val task1 = Task("Title1", "Description1")
        val task2 = Task("Title2", "Description2", true)
        val task3 = Task("Title3", "Description3", true)
        tasksRepository.addTasks(task1, task2, task3)

        tasksViewModel = TasksViewModel(tasksRepository)
        
    }
  1. যেহেতু আপনি আর অ্যান্ড্রয়েডএক্স টেস্ট ApplicationProvider.getApplicationContext কোড ব্যবহার করছেন না, আপনি @RunWith(AndroidJUnit4::class) টীকাগুলিও সরিয়ে ফেলতে পারেন।
  2. আপনার পরীক্ষাগুলি চালান, নিশ্চিত করুন যে তারা এখনও সমস্ত কাজ করে!

কনস্ট্রাক্টর নির্ভরতা ইনজেকশন ব্যবহার করে, আপনি এখন নির্ভরতা হিসাবে DefaultTasksRepository সরিয়ে ফেলেছেন এবং এটি পরীক্ষাগুলিতে আপনার FakeTestRepository সাথে প্রতিস্থাপন করেছেন।

পদক্ষেপ 3। এছাড়াও টাস্কডেটেল খণ্ড এবং ভিউমোডেল আপডেট করুন

TaskDetailFragment এবং TaskDetailViewModel জন্য ঠিক একই পরিবর্তনগুলি করুন। আপনি যখন TaskDetail পরীক্ষাগুলি লিখবেন তখন এটি কোডটি প্রস্তুত করবে।

  1. TaskDetailViewModel খুলুন
  2. কনস্ট্রাক্টর আপডেট করুন:

টাস্কডেটাইলভিউমোডেল.কেটি

// REPLACE
class TaskDetailViewModel(application: Application) : AndroidViewModel(application) {

    private val tasksRepository = DefaultTasksRepository.getRepository(application)

    // Rest of class
}

// WITH

class TaskDetailViewModel(
    private val tasksRepository: TasksRepository
) : ViewModel() { // Rest of class }
  1. ক্লাসের বাইরে TaskDetailViewModel ফাইলের নীচে, একটি TaskDetailViewModelFactory যুক্ত করুন।

টাস্কডেটাইলভিউমোডেল.কেটি

@Suppress("UNCHECKED_CAST")
class TaskDetailViewModelFactory (
    private val tasksRepository: TasksRepository
) : ViewModelProvider.NewInstanceFactory() {
    override fun <T : ViewModel> create(modelClass: Class<T>) =
        (TaskDetailViewModel(tasksRepository) as T)
}
  1. কারখানাটি ব্যবহার করতে TasksFragment আপডেট করুন।

টাস্কসফ্র্যাগমেন্ট.কেটি

// REPLACE
private val viewModel by viewModels<TaskDetailViewModel>()

// WITH

private val viewModel by viewModels<TaskDetailViewModel> {
    TaskDetailViewModelFactory(DefaultTasksRepository.getRepository(requireActivity().application))
}
  1. আপনার কোডটি চালান এবং নিশ্চিত করুন যে সবকিছু কাজ করছে।

আপনি এখন TasksFragment এবং TasksDetailFragment আসল ভাণ্ডারগুলির পরিবর্তে একটি FakeTestRepository ব্যবহার করতে সক্ষম।

এরপরে আপনি আপনার খণ্ড এবং ভিউ-মডেল ইন্টারঅ্যাকশনগুলি পরীক্ষা করতে ইন্টিগ্রেশন পরীক্ষা লিখবেন। আপনার ভিউ মডেল কোডটি যথাযথভাবে আপনার ইউআই আপডেট করে কিনা তা আপনি খুঁজে পাবেন। এটি করতে আপনি ব্যবহার করেন

  • সার্ভিসলোকেটর প্যাটার্ন
  • এস্প্রেসো এবং মকিটো লাইব্রেরি

ইন্টিগ্রেশন টেস্টগুলি বেশ কয়েকটি শ্রেণীর মিথস্ক্রিয়া পরীক্ষা করে তা নিশ্চিত করার জন্য তারা একসাথে ব্যবহার করার সময় প্রত্যাশা অনুযায়ী আচরণ করে। এই পরীক্ষাগুলি স্থানীয়ভাবে ( test উত্স সেট) বা ইনস্ট্রুমেন্টেশন পরীক্ষা হিসাবে ( androidTest উত্স সেট) চালানো যেতে পারে।

আপনার ক্ষেত্রে আপনি খণ্ডটির মূল বৈশিষ্ট্যগুলি পরীক্ষা করতে প্রতিটি খণ্ড এবং খণ্ডের জন্য ইন্টিগ্রেশন পরীক্ষাগুলি গ্রহণ করবেন এবং মডেলের জন্য লিখবেন।

পদক্ষেপ 1। গ্রেডল নির্ভরতা যুক্ত করুন

  1. নিম্নলিখিত গ্রেডল নির্ভরতা যুক্ত করুন।

অ্যাপ্লিকেশন/বিল্ড.গ্রাডল

    // Dependencies for Android instrumented unit tests
    androidTestImplementation "junit:junit:$junitVersion"
    androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"

    // Testing code should not be included in the main code.
    // Once https://issuetracker.google.com/128612536 is fixed this can be fixed.

    implementation "androidx.fragment:fragment-testing:$fragmentVersion"
    implementation "androidx.test:core:$androidXTestCoreVersion"

এই নির্ভরতাগুলির মধ্যে রয়েছে:

  • junit:junit -জুনিত, যা প্রাথমিক পরীক্ষার বিবৃতি লেখার জন্য প্রয়োজনীয়।
  • androidx.test:core -কোর অ্যান্ড্রয়েডএক্স টেস্ট লাইব্রেরি
  • kotlinx-coroutines-test -করুটাইন টেস্টিং লাইব্রেরি
  • androidx.fragment:fragment-testing টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো

যেহেতু আপনি এই লাইব্রেরিগুলি আপনার androidTest উত্স সেটটিতে ব্যবহার করবেন, তাই তাদের নির্ভরতা হিসাবে যুক্ত করতে androidTestImplementation ব্যবহার করুন।

পদক্ষেপ 2। একটি টাস্কডেটেলফ্র্যাগমেন্টস্টেস্ট ক্লাস করুন

TaskDetailFragment একটি একক কাজ সম্পর্কে তথ্য দেখায়।

আপনি অন্যান্য খণ্ডগুলির তুলনায় মোটামুটি মৌলিক কার্যকারিতা রয়েছে বলে TaskDetailFragment জন্য একটি খণ্ড পরীক্ষা লিখে আপনি শুরু করবেন।

  1. taskdetail.TaskDetailFragment খুলুন
  2. আপনি আগে যেমন করেছেন তেমন TaskDetailFragment জন্য একটি পরীক্ষা তৈরি করুন । ডিফল্ট পছন্দগুলি গ্রহণ করুন এবং এটি অ্যান্ড্রয়েডটেস্ট উত্স সেটে রাখুন ( test উত্স সেট নয়)।

  1. TaskDetailFragmentTest ক্লাসে নিম্নলিখিত টীকাগুলি যুক্ত করুন।

টাস্কডেটেলফ্র্যাগমেন্ট টেস্ট.কেটি

@MediumTest
@RunWith(AndroidJUnit4::class)
class TaskDetailFragmentTest {

}

এই টীকাটির উদ্দেশ্য হ'ল:

  • @MediumTest টেস্ট-পরীক্ষাটিকে একটি "মাঝারি রান-টাইম" ইন্টিগ্রেশন টেস্ট হিসাবে চিহ্নিত করে (বনাম @SmallTest ইউনিট পরীক্ষা এবং @LargeTest লার্জ এন্ড-টু-এন্ড টেস্ট)। এটি আপনাকে গোষ্ঠী করতে এবং কোন আকারের পরীক্ষার চালাতে হবে তা বেছে নিতে সহায়তা করে।
  • @RunWith(AndroidJUnit4::class) - অ্যান্ড্রয়েডএক্স পরীক্ষা ব্যবহার করে যে কোনও ক্লাসে ব্যবহৃত।

পদক্ষেপ 3। একটি পরীক্ষা থেকে একটি খণ্ড চালু করুন

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

  1. এই পরীক্ষাটি TaskDetailFragmentTest অনুলিপি করুন

টাস্কডেটেলফ্র্যাগমেন্ট টেস্ট.কেটি

    @Test
    fun activeTaskDetails_DisplayedInUi() {
        // GIVEN - Add active (incomplete) task to the DB
        val activeTask = Task("Active Task", "AndroidX Rocks", false)

        // WHEN - Details fragment launched to display task
        val bundle = TaskDetailFragmentArgs(activeTask.id).toBundle()
        launchFragmentInContainer<TaskDetailFragment>(bundle, R.style.AppTheme)

    }

উপরের এই কোড:

  • একটি কাজ তৈরি করে।
  • একটি Bundle তৈরি করে, যা টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো
  • launchFragmentInContainer ফাংশনটি এই বান্ডিল এবং একটি থিম সহ একটি FragmentScenario তৈরি করে।

এটি এখনও কোনও সমাপ্ত পরীক্ষা নয়, কারণ এটি কোনও কিছু জোর দিচ্ছে না। আপাতত, পরীক্ষা চালান এবং কী ঘটে তা পর্যবেক্ষণ করুন।

  1. এটি একটি সরঞ্জামযুক্ত পরীক্ষা, সুতরাং নিশ্চিত করুন যে এমুলেটর বা আপনার ডিভাইসটি দৃশ্যমান।
  2. পরীক্ষা চালান

কয়েকটি জিনিস হওয়া উচিত।

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

অবশেষে, ঘনিষ্ঠভাবে দেখুন এবং লক্ষ্য করুন যে খণ্ডটি "কোনও ডেটা" বলে কারণ এটি সফলভাবে টাস্ক ডেটা লোড করে না।

আপনার পরীক্ষা উভয়কেই TaskDetailFragment (যা আপনি করেছেন) লোড করতে হবে এবং ডেটা সঠিকভাবে লোড করা হয়েছে বলে দৃ sert ়ভাবে দাবি করা উচিত। কেন কোনও ডেটা নেই? এটি কারণ আপনি কোনও কাজ তৈরি করেছেন, তবে আপনি এটি সংগ্রহস্থলে সংরক্ষণ করেননি।

    @Test
    fun activeTaskDetails_DisplayedInUi() {
        // This DOES NOT save the task anywhere
        val activeTask = Task("Active Task", "AndroidX Rocks", false)

        val bundle = TaskDetailFragmentArgs(activeTask.id).toBundle()
        launchFragmentInContainer<TaskDetailFragment>(bundle, R.style.AppTheme)

    }

আপনার কাছে এই FakeTestRepository রয়েছে তবে আপনার খণ্ডের জন্য আপনার আসল ভান্ডারটি আপনার নকলটির সাথে প্রতিস্থাপনের জন্য আপনার কিছু উপায় প্রয়োজন। আপনি এটি পরবর্তী করবেন!

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

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

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

পরিষেবা লোকেটার ব্যবহার করছেন না


একটি পরিষেবা লোকেটার ব্যবহার করে

এই কোডল্যাব অ্যাপের জন্য, নিম্নলিখিতগুলি করুন:

  1. একটি পরিষেবা লোকেটার ক্লাস তৈরি করুন যা একটি সংগ্রহস্থল তৈরি এবং সঞ্চয় করতে সক্ষম। ডিফল্টরূপে এটি একটি "সাধারণ" সংগ্রহস্থল তৈরি করে।
  2. আপনার কোডটি রিফ্যাক্টর করুন যাতে আপনার যখন কোনও সংগ্রহস্থল প্রয়োজন হয় তখন পরিষেবা লোকেটারটি ব্যবহার করুন।
  3. আপনার টেস্টিং ক্লাসে, পরিষেবা লোকেটারে এমন একটি পদ্ধতিতে কল করুন যা আপনার পরীক্ষার দ্বিগুণ "সাধারণ" সংগ্রহস্থলটি অদলবদল করে।

পদক্ষেপ 1। সার্ভিসলোকেটর তৈরি করুন

আসুন একটি ServiceLocator ক্লাস করা যাক। এটি অ্যাপ্লিকেশন কোডের বাকী অংশের সাথে মূল উত্স সেটটিতে বাস করবে কারণ এটি মূল অ্যাপ্লিকেশন কোড দ্বারা ব্যবহৃত হয়।

দ্রষ্টব্য: ServiceLocator একটি সিঙ্গলটন, তাই ক্লাসের জন্য কোটলিন object কীওয়ার্ডটি ব্যবহার করুন।

  1. মূল উত্স সেটটির শীর্ষ স্তরে সার্ভিসলোকেটর.কেটি ফাইলটি তৈরি করুন।
  2. ServiceLocator নামে একটি object সংজ্ঞায়িত করুন।
  3. database এবং repository উদাহরণ ভেরিয়েবলগুলি তৈরি করুন এবং উভয়কে null সেট করুন।
  4. @Volatile সাথে সংগ্রহস্থলটিকে টীকা দিন কারণ এটি একাধিক থ্রেড দ্বারা ব্যবহৃত হতে পারে ( @Volatile এখানে বিশদভাবে ব্যাখ্যা করা হয়েছে)।

আপনার কোডটি নীচে প্রদর্শিত হিসাবে দেখা উচিত।

object ServiceLocator {

    private var database: ToDoDatabase? = null
    @Volatile
    var tasksRepository: TasksRepository? = null

}

এই মুহুর্তে আপনার ServiceLocator কেবলমাত্র একটি TasksRepository ফেরত দিতে হবে তা জানা। এটি একটি প্রাক-বিদ্যমান DefaultTasksRepository ফেরত দেবে বা প্রয়োজনে একটি নতুন DefaultTasksRepository তৈরি করবে এবং ফিরিয়ে দেবে।

নিম্নলিখিত ফাংশনগুলি সংজ্ঞায়িত করুন:

  1. provideTasksRepository - হয় ইতিমধ্যে একটি বিদ্যমান সংগ্রহস্থল সরবরাহ করে বা একটি নতুন তৈরি করে। একাধিক থ্রেড চলমান পরিস্থিতিতে এড়াতে এই পদ্ধতিটি this synchronized করা উচিত, কখনও দুর্ঘটনাক্রমে দুটি সংগ্রহস্থল উদাহরণ তৈরি করে।
  2. একটি নতুন সংগ্রহস্থল তৈরির জন্য createTasksRepository - কোড। createTaskLocalDataSource কল করবে এবং একটি নতুন TasksRemoteDataSource তৈরি করবে।
  3. একটি নতুন স্থানীয় ডেটা উত্স তৈরি করার জন্য createTaskLocalDataSource • কোড। createDataBase কল করবে।
  4. একটি নতুন ডাটাবেস তৈরির জন্য createDataBase -কোড।

সম্পূর্ণ কোডটি নীচে রয়েছে।

সার্ভিসলোকেটর.কেটি

object ServiceLocator {

    private var database: ToDoDatabase? = null
    @Volatile
    var tasksRepository: TasksRepository? = null

    fun provideTasksRepository(context: Context): TasksRepository {
        synchronized(this) {
            return tasksRepository ?: createTasksRepository(context)
        }
    }

    private fun createTasksRepository(context: Context): TasksRepository {
        val newRepo = DefaultTasksRepository(TasksRemoteDataSource, createTaskLocalDataSource(context))
        tasksRepository = newRepo
        return newRepo
    }

    private fun createTaskLocalDataSource(context: Context): TasksDataSource {
        val database = database ?: createDataBase(context)
        return TasksLocalDataSource(database.taskDao())
    }

    private fun createDataBase(context: Context): ToDoDatabase {
        val result = Room.databaseBuilder(
            context.applicationContext,
            ToDoDatabase::class.java, "Tasks.db"
        ).build()
        database = result
        return result
    }
}

পদক্ষেপ 2। অ্যাপ্লিকেশনটিতে সার্ভিসোলোকেটর ব্যবহার করুন

আপনি আপনার প্রধান অ্যাপ্লিকেশন কোডে পরিবর্তন আনতে যাচ্ছেন (আপনার পরীক্ষাগুলি নয়) যাতে আপনি এক জায়গায় ভান্ডার তৈরি করেন, আপনার ServiceLocator

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

  1. আপনার প্যাকেজ শ্রেণিবিন্যাসের শীর্ষ স্তরে, TodoApplication খুলুন এবং আপনার সংগ্রহস্থলের জন্য একটি val তৈরি করুন এবং এটিকে একটি সংগ্রহস্থল নির্ধারণ করুন যা ServiceLocator.provideTaskRepository ব্যবহার করে প্রাপ্ত হয়।

Todoapplication.kt

class TodoApplication : Application() {

    val taskRepository: TasksRepository
        get() = ServiceLocator.provideTasksRepository(this)

    override fun onCreate() {
        super.onCreate()
        if (BuildConfig.DEBUG) Timber.plant(DebugTree())
    }
}

এখন যেহেতু আপনি অ্যাপ্লিকেশনটিতে একটি সংগ্রহস্থল তৈরি করেছেন, আপনি DefaultTasksRepository পুরানো getRepository পদ্ধতিটি সরিয়ে ফেলতে পারেন।

  1. DefaultTasksRepository খুলুন এবং সহযোগী অবজেক্টটি মুছুন।

Defaulttasksrepository.kt

// DELETE THIS COMPANION OBJECT
companion object {
    @Volatile
    private var INSTANCE: DefaultTasksRepository? = null

    fun getRepository(app: Application): DefaultTasksRepository {
        return INSTANCE ?: synchronized(this) {
            val database = Room.databaseBuilder(app,
                ToDoDatabase::class.java, "Tasks.db")
                .build()
            DefaultTasksRepository(TasksRemoteDataSource, TasksLocalDataSource(database.taskDao())).also {
                INSTANCE = it
            }
        }
    }
}

এখন আপনি যেদিকেই getRepository ব্যবহার করছেন, পরিবর্তে অ্যাপ্লিকেশনটির taskRepository ব্যবহার করুন। এটি নিশ্চিত করে যে সরাসরি সংগ্রহস্থলটি তৈরি করার পরিবর্তে, আপনি ServiceLocator সরবরাহকারী যা কিছু সংগ্রহস্থল পাচ্ছেন তা পাচ্ছেন।

  1. TaskDetailFragement খুলুন এবং ক্লাসের শীর্ষে getRepository কলটি সন্ধান করুন।
  2. এই কলটি এমন একটি কল দিয়ে প্রতিস্থাপন করুন যা TodoApplication থেকে সংগ্রহস্থল পায়।

টাস্কডেটাইলফ্র্যাগমেন্ট.কেটি

// REPLACE this code
private val viewModel by viewModels<TaskDetailViewModel> {
    TaskDetailViewModelFactory(DefaultTasksRepository.getRepository(requireActivity().application))
}

// WITH this code

private val viewModel by viewModels<TaskDetailViewModel> {
    TaskDetailViewModelFactory((requireContext().applicationContext as TodoApplication).taskRepository)
}
  1. TasksFragment জন্য একই করুন।

টাস্কসফ্র্যাগমেন্ট.কেটি

// REPLACE this code
    private val viewModel by viewModels<TasksViewModel> {
        TasksViewModelFactory(DefaultTasksRepository.getRepository(requireActivity().application))
    }


// WITH this code

    private val viewModel by viewModels<TasksViewModel> {
        TasksViewModelFactory((requireContext().applicationContext as TodoApplication).taskRepository)
    }
  1. StatisticsViewModel এবং AddEditTaskViewModel জন্য, TodoApplication থেকে সংগ্রহস্থলটি ব্যবহার করার জন্য সংগ্রহস্থলটি অর্জন করে এমন কোডটি আপডেট করুন।

টাস্কসফ্র্যাগমেন্ট.কেটি

// REPLACE this code
    private val tasksRepository = DefaultTasksRepository.getRepository(application)



// WITH this code

    private val tasksRepository = (application as TodoApplication).taskRepository

  1. আপনার আবেদন চালান (পরীক্ষা নয়)!

যেহেতু আপনি কেবল রিফ্যাক্ট করেছেন, অ্যাপটি ইস্যু ছাড়াই একই চালানো উচিত।

পদক্ষেপ 3। ফেকএন্ড্রয়েডটেস্টপ্রেসিটরি তৈরি করুন

আপনার ইতিমধ্যে পরীক্ষার উত্স সেটটিতে একটি FakeTestRepository রয়েছে। আপনি ডিফল্টরূপে test এবং androidTest উত্স সেটগুলির মধ্যে পরীক্ষার ক্লাসগুলি ভাগ করতে পারবেন না। সুতরাং, আপনাকে androidTest উত্স সেটটিতে একটি সদৃশ FakeTestRepository ক্লাস তৈরি করতে হবে এবং এটিকে FakeAndroidTestRepository কল করতে হবে।

  1. androidTest উত্স সেটটিতে ডান ক্লিক করুন এবং একটি ডেটা প্যাকেজ তৈরি করুন। আবার ডান ক্লিক করুন এবং একটি উত্স প্যাকেজ তৈরি করুন।
  2. এই উত্স প্যাকেজে একটি নতুন শ্রেণি তৈরি করুন যা FakeAndroidTestRepository.kt নামে পরিচিত।
  3. নিম্নলিখিত কোডটি সেই শ্রেণিতে অনুলিপি করুন।

Fakeandroidtestrepository.kt

import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import com.example.android.architecture.blueprints.todoapp.data.Result
import com.example.android.architecture.blueprints.todoapp.data.Result.Error
import com.example.android.architecture.blueprints.todoapp.data.Result.Success
import com.example.android.architecture.blueprints.todoapp.data.Task
import kotlinx.coroutines.runBlocking
import java.util.LinkedHashMap



class FakeAndroidTestRepository : TasksRepository {

    var tasksServiceData: LinkedHashMap<String, Task> = LinkedHashMap()

    private var shouldReturnError = false

    private val observableTasks = MutableLiveData<Result<List<Task>>>()

    fun setReturnError(value: Boolean) {
        shouldReturnError = value
    }

    override suspend fun refreshTasks() {
        observableTasks.value = getTasks()
    }

    override suspend fun refreshTask(taskId: String) {
        refreshTasks()
    }

    override fun observeTasks(): LiveData<Result<List<Task>>> {
        runBlocking { refreshTasks() }
        return observableTasks
    }

    override fun observeTask(taskId: String): LiveData<Result<Task>> {
        runBlocking { refreshTasks() }
        return observableTasks.map { tasks ->
            when (tasks) {
                is Result.Loading -> Result.Loading
                is Error -> Error(tasks.exception)
                is Success -> {
                    val task = tasks.data.firstOrNull() { it.id == taskId }
                        ?: return@map Error(Exception("Not found"))
                    Success(task)
                }
            }
        }
    }

    override suspend fun getTask(taskId: String, forceUpdate: Boolean): Result<Task> {
        if (shouldReturnError) {
            return Error(Exception("Test exception"))
        }
        tasksServiceData[taskId]?.let {
            return Success(it)
        }
        return Error(Exception("Could not find task"))
    }

    override suspend fun getTasks(forceUpdate: Boolean): Result<List<Task>> {
        if (shouldReturnError) {
            return Error(Exception("Test exception"))
        }
        return Success(tasksServiceData.values.toList())
    }

    override suspend fun saveTask(task: Task) {
        tasksServiceData[task.id] = task
    }

    override suspend fun completeTask(task: Task) {
        val completedTask = Task(task.title, task.description, true, task.id)
        tasksServiceData[task.id] = completedTask
    }

    override suspend fun completeTask(taskId: String) {
        // Not required for the remote data source.
        throw NotImplementedError()
    }

    override suspend fun activateTask(task: Task) {
        val activeTask = Task(task.title, task.description, false, task.id)
        tasksServiceData[task.id] = activeTask
    }

    override suspend fun activateTask(taskId: String) {
        throw NotImplementedError()
    }

    override suspend fun clearCompletedTasks() {
        tasksServiceData = tasksServiceData.filterValues {
            !it.isCompleted
        } as LinkedHashMap<String, Task>
    }

    override suspend fun deleteTask(taskId: String) {
        tasksServiceData.remove(taskId)
        refreshTasks()
    }

    override suspend fun deleteAllTasks() {
        tasksServiceData.clear()
        refreshTasks()
    }

   
    fun addTasks(vararg tasks: Task) {
        for (task in tasks) {
            tasksServiceData[task.id] = task
        }
        runBlocking { refreshTasks() }
    }
}

পদক্ষেপ 4। পরীক্ষার জন্য আপনার সার্ভিসলোকেটর প্রস্তুত করুন

ঠিক আছে, পরীক্ষার সময় টেস্ট ডাবলগুলিতে অদলবদল করার জন্য ServiceLocator ব্যবহার করার সময়। এটি করার জন্য, আপনাকে আপনার ServiceLocator কোডে কিছু কোড যুক্ত করতে হবে।

  1. ওপেন ServiceLocator.kt
  2. tasksRepository জন্য সেটারটিকে @VisibleForTesting হিসাবে চিহ্নিত করুন। এই টীকাটি প্রকাশ করার একটি উপায় যে সেটারটি সর্বজনীন হওয়ার কারণটি পরীক্ষার কারণে।

সার্ভিসলোকেটর.কেটি

    @Volatile
    var tasksRepository: TasksRepository? = null
        @VisibleForTesting set

আপনি একা আপনার পরীক্ষা চালান বা একদল পরীক্ষার মধ্যে থাকুক না কেন, আপনার পরীক্ষাগুলি ঠিক একই রকম চলবে। এর অর্থ হ'ল আপনার পরীক্ষাগুলির এমন কোনও আচরণ করা উচিত নয় যা একে অপরের উপর নির্ভরশীল (যার অর্থ পরীক্ষার মধ্যে ভাগ করে নেওয়া এড়ানো)।

যেহেতু ServiceLocator একটি সিঙ্গেলটন, তাই এটি পরীক্ষাগুলির মধ্যে দুর্ঘটনাক্রমে ভাগ করে নেওয়ার সম্ভাবনা রয়েছে। এটি এড়াতে সহায়তা করার জন্য, এমন একটি পদ্ধতি তৈরি করুন যা পরীক্ষার মধ্যে ServiceLocator রাষ্ট্রকে সঠিকভাবে পুনরায় সেট করে।

  1. Any মান সহ lock নামে একটি উদাহরণ ভেরিয়েবল যুক্ত করুন।

সার্ভিসলোকেটর.কেটি

private val lock = Any()
  1. resetRepository নামক একটি টেস্টিং-নির্দিষ্ট পদ্ধতি যুক্ত করুন যা ডাটাবেসটি পরিষ্কার করে এবং সংগ্রহস্থল এবং ডাটাবেস উভয়ই নালিতে সেট করে।

সার্ভিসলোকেটর.কেটি

    @VisibleForTesting
    fun resetRepository() {
        synchronized(lock) {
            runBlocking {
                TasksRemoteDataSource.deleteAllTasks()
            }
            // Clear all data to avoid test pollution.
            database?.apply {
                clearAllTables()
                close()
            }
            database = null
            tasksRepository = null
        }
    }

পদক্ষেপ 5। আপনার সার্ভিসলোকেটর ব্যবহার করুন

এই পদক্ষেপে, আপনি ServiceLocator ব্যবহার করেন।

  1. TaskDetailFragmentTest টেস্ট খুলুন
  2. একটি lateinit TasksRepository ভেরিয়েবল ঘোষণা করুন।
  3. প্রতিটি পরীক্ষার আগে একটি FakeAndroidTestRepository সেট আপ করতে একটি সেটআপ এবং একটি টিয়ার ডাউন পদ্ধতি যুক্ত করুন এবং প্রতিটি পরীক্ষার পরে এটি পরিষ্কার করুন।

টাস্কডেটেলফ্র্যাগমেন্ট টেস্ট.কেটি

    private lateinit var repository: TasksRepository

    @Before
    fun initRepository() {
        repository = FakeAndroidTestRepository()
        ServiceLocator.tasksRepository = repository
    }

    @After
    fun cleanupDb() = runBlockingTest {
        ServiceLocator.resetRepository()
    }
  1. runBlockingTest টেস্টে activeTaskDetails_DisplayedInUi() এর ফাংশন বডিটি মোড়ানো।
  2. খণ্ডটি চালু করার আগে সংগ্রহস্থলে activeTask সংরক্ষণ করুন।
repository.saveTask(activeTask)

চূড়ান্ত পরীক্ষাটি নীচে এই কোডের মতো দেখাচ্ছে।

টাস্কডেটেলফ্র্যাগমেন্ট টেস্ট.কেটি

    @Test
    fun activeTaskDetails_DisplayedInUi()  = runBlockingTest{
        // GIVEN - Add active (incomplete) task to the DB
        val activeTask = Task("Active Task", "AndroidX Rocks", false)
        repository.saveTask(activeTask)

        // WHEN - Details fragment launched to display task
        val bundle = TaskDetailFragmentArgs(activeTask.id).toBundle()
        launchFragmentInContainer<TaskDetailFragment>(bundle, R.style.AppTheme)

    }
  1. @ExperimentalCoroutinesApi দিয়ে পুরো ক্লাসটি টীকা দিন।

শেষ হয়ে গেলে কোডটি এর মতো দেখাবে।

টাস্কডেটেলফ্র্যাগমেন্ট টেস্ট.কেটি

@MediumTest
@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
class TaskDetailFragmentTest {

    private lateinit var repository: TasksRepository

    @Before
    fun initRepository() {
        repository = FakeAndroidTestRepository()
        ServiceLocator.tasksRepository = repository
    }

    @After
    fun cleanupDb() = runBlockingTest {
        ServiceLocator.resetRepository()
    }


    @Test
    fun activeTaskDetails_DisplayedInUi()  = runBlockingTest{
        // GIVEN - Add active (incomplete) task to the DB
        val activeTask = Task("Active Task", "AndroidX Rocks", false)
        repository.saveTask(activeTask)

        // WHEN - Details fragment launched to display task
        val bundle = TaskDetailFragmentArgs(activeTask.id).toBundle()
        launchFragmentInContainer<TaskDetailFragment>(bundle, R.style.AppTheme)

    }

}
  1. activeTaskDetails_DisplayedInUi() পরীক্ষা চালান।

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


এই পদক্ষেপে, আপনি আপনার প্রথম ইন্টিগ্রেশন পরীক্ষা সম্পূর্ণ করতে এস্প্রেসো ইউআই টেস্টিং লাইব্রেরি ব্যবহার করবেন। আপনি আপনার কোডটি কাঠামোগত করেছেন যাতে আপনি আপনার ইউআইয়ের জন্য দৃ ser ়তার সাথে পরীক্ষাগুলি যুক্ত করতে পারেন। এটি করার জন্য, আপনি এস্প্রেসো টেস্টিং লাইব্রেরি ব্যবহার করবেন।

এস্প্রেসো আপনাকে সহায়তা করে:

  • ভিউগুলির সাথে ইন্টারঅ্যাক্ট করুন, যেমন বোতামগুলি ক্লিক করা, একটি বার স্লাইডিং করা বা কোনও স্ক্রিনে স্ক্রোল করা।
  • দৃ sert ়ভাবে জানান যে নির্দিষ্ট ভিউগুলি স্ক্রিনে রয়েছে বা একটি নির্দিষ্ট অবস্থায় রয়েছে (যেমন নির্দিষ্ট পাঠ্যযুক্ত, বা একটি চেকবক্স চেক করা হয় ইত্যাদি)।

পদক্ষেপ 1। নোট গ্রেডল নির্ভরতা

এটি ডিফল্টরূপে অ্যান্ড্রয়েড প্রকল্পগুলিতে অন্তর্ভুক্ত হওয়ায় আপনার ইতিমধ্যে প্রধান এস্প্রেসো নির্ভরতা থাকবে।

অ্যাপ্লিকেশন/বিল্ড.গ্রাডল

dependencies {

  // ALREADY in your code
    androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
   
 // Other dependencies
}

androidx.test.espresso:espresso-core -এই কোর এস্প্রেসো নির্ভরতা ডিফল্টরূপে অন্তর্ভুক্ত করা হয় যখন আপনি একটি নতুন অ্যান্ড্রয়েড প্রকল্প তৈরি করেন। এটিতে বেশিরভাগ দর্শন এবং ক্রিয়াকলাপের জন্য প্রাথমিক পরীক্ষার কোড রয়েছে।

পদক্ষেপ 2। অ্যানিমেশনগুলি বন্ধ করুন

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

এস্প্রেসো ইউআই পরীক্ষার জন্য, অ্যানিমেশনগুলি বন্ধ করা ভাল অনুশীলন (এছাড়াও আপনার পরীক্ষাটি দ্রুত চলবে!):

  1. আপনার পরীক্ষার ডিভাইসে, সেটিংস> বিকাশকারী বিকল্পগুলিতে যান।
  2. এই তিনটি সেটিংস অক্ষম করুন: উইন্ডো অ্যানিমেশন স্কেল , ট্রানজিশন অ্যানিমেশন স্কেল এবং অ্যানিমেটার সময়কাল স্কেল

পদক্ষেপ 3। একটি এস্প্রেসো পরীক্ষা দেখুন

আপনি একটি এস্প্রেসো পরীক্ষা লেখার আগে, কিছু এস্প্রেসো কোডটি একবার দেখুন।

onView(withId(R.id.task_detail_complete_checkbox)).perform(click()).check(matches(isChecked()))

এই বিবৃতিটি যা করে তা হ'ল আইডি task_detail_complete_checkbox সাথে চেকবক্স ভিউটি খুঁজে পাওয়া, এটি ক্লিক করে, তারপরে এটি পরীক্ষা করা হয়েছে বলে দৃ sert ়ভাবে দাবি করে।

এস্প্রেসো বিবৃতিগুলির বেশিরভাগ অংশ চারটি অংশ নিয়ে গঠিত:

1। স্ট্যাটিক এস্প্রেসো পদ্ধতি

onView

onView একটি স্ট্যাটিক এস্প্রেসো পদ্ধতির একটি উদাহরণ যা একটি এস্প্রেসো বিবৃতি শুরু করে। onView সর্বাধিক সাধারণ একটি, তবে অন্যান্য বিকল্প যেমন onData রয়েছে।

2। ভিউম্যাচার

withId(R.id.task_detail_title_text)

withId হ'ল ViewMatcher একটি উদাহরণ যা এর আইডি দ্বারা একটি দর্শন পায়। অন্যান্য ভিউ ম্যাচার রয়েছে যা আপনি ডকুমেন্টেশনে সন্ধান করতে পারেন।

3। ভিউ

perform(click())

perform পদ্ধতি যা একটি ViewAction নেয়। একটি ViewAction হ'ল এমন কিছু যা ভিউতে করা যায়, উদাহরণস্বরূপ এখানে এটি দৃশ্যে ক্লিক করছে।

4। ভিউসেসারশন

check(matches(isChecked()))

কোনটি ViewAssertion লাগে তা checkViewAssertion এস চেক বা ভিউ সম্পর্কে কিছু জোর দেয়। আপনি যে সর্বাধিক সাধারণ ViewAssertion ব্যবহার করবেন তা হ'ল matches দৃ ser ়তা। দৃ ser ়তা শেষ করতে, অন্য একটি ViewMatcher ব্যবহার করুন, এক্ষেত্রে isChecked

নোট করুন যে আপনি সর্বদা perform কল করেন না এবং একটি এস্প্রেসো বিবৃতিতে check । আপনার কাছে এমন বিবৃতি থাকতে পারে যা কেবল check ব্যবহার করে একটি দৃ ser ়তা তৈরি করে বা কেবল perform ব্যবহার করে একটি ViewAction করুন।

  1. TaskDetailFragmentTest.kt টেস্ট.কেটি খুলুন
  2. activeTaskDetails_DisplayedInUi পরীক্ষা আপডেট করুন

টাস্কডেটেলফ্র্যাগমেন্ট টেস্ট.কেটি

    @Test
    fun activeTaskDetails_DisplayedInUi() = runBlockingTest{
        // GIVEN - Add active (incomplete) task to the DB
        val activeTask = Task("Active Task", "AndroidX Rocks", false)
        repository.saveTask(activeTask)

        // WHEN - Details fragment launched to display task
        val bundle = TaskDetailFragmentArgs(activeTask.id).toBundle()
        launchFragmentInContainer<TaskDetailFragment>(bundle, R.style.AppTheme)

        // THEN - Task details are displayed on the screen
        // make sure that the title/description are both shown and correct
        onView(withId(R.id.task_detail_title_text)).check(matches(isDisplayed()))
        onView(withId(R.id.task_detail_title_text)).check(matches(withText("Active Task")))
        onView(withId(R.id.task_detail_description_text)).check(matches(isDisplayed()))
        onView(withId(R.id.task_detail_description_text)).check(matches(withText("AndroidX Rocks")))
        // and make sure the "active" checkbox is shown unchecked
        onView(withId(R.id.task_detail_complete_checkbox)).check(matches(isDisplayed()))
        onView(withId(R.id.task_detail_complete_checkbox)).check(matches(not(isChecked())))
    }

প্রয়োজনে আমদানি বিবৃতি এখানে:

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isChecked
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import org.hamcrest.core.IsNot.not
  1. // THEN পরে সমস্ত কিছু মন্তব্য এস্প্রেসো ব্যবহার করে। পরীক্ষার কাঠামো এবং withId এর ব্যবহার পরীক্ষা করুন এবং বিশদ পৃষ্ঠাটি কীভাবে দেখতে হবে সে সম্পর্কে দৃ ser ়তা তৈরি করতে পরীক্ষা করুন।
  2. পরীক্ষা চালান এবং এটি পাস হয়েছে তা নিশ্চিত করুন।

পদক্ষেপ 4। al চ্ছিক, আপনার নিজের এস্প্রেসো পরীক্ষা লিখুন

এখন নিজেই একটি পরীক্ষা লিখুন।

  1. completedTaskDetails_DisplayedInUi নামে একটি নতুন পরীক্ষা তৈরি করুন এবং এই কঙ্কাল কোডটি অনুলিপি করুন।

টাস্কডেটেলফ্র্যাগমেন্ট টেস্ট.কেটি

    @Test
    fun completedTaskDetails_DisplayedInUi() = runBlockingTest{
        // GIVEN - Add completed task to the DB
       
        // WHEN - Details fragment launched to display task
        
        // THEN - Task details are displayed on the screen
        // make sure that the title/description are both shown and correct
}
  1. পূর্ববর্তী পরীক্ষার দিকে তাকিয়ে, এই পরীক্ষাটি সম্পূর্ণ করুন
  2. চালান এবং পরীক্ষা পাসগুলি নিশ্চিত করুন।

সমাপ্ত completedTaskDetails_DisplayedInUi এই কোডটির মতো দেখা উচিত।

টাস্কডেটেলফ্র্যাগমেন্ট টেস্ট.কেটি

    @Test
    fun completedTaskDetails_DisplayedInUi() = runBlockingTest{
        // GIVEN - Add completed task to the DB
        val completedTask = Task("Completed Task", "AndroidX Rocks", true)
        repository.saveTask(completedTask)

        // WHEN - Details fragment launched to display task
        val bundle = TaskDetailFragmentArgs(completedTask.id).toBundle()
        launchFragmentInContainer<TaskDetailFragment>(bundle, R.style.AppTheme)

        // THEN - Task details are displayed on the screen
        // make sure that the title/description are both shown and correct
        onView(withId(R.id.task_detail_title_text)).check(matches(isDisplayed()))
        onView(withId(R.id.task_detail_title_text)).check(matches(withText("Completed Task")))
        onView(withId(R.id.task_detail_description_text)).check(matches(isDisplayed()))
        onView(withId(R.id.task_detail_description_text)).check(matches(withText("AndroidX Rocks")))
        // and make sure the "active" checkbox is shown unchecked
        onView(withId(R.id.task_detail_complete_checkbox)).check(matches(isDisplayed()))
        onView(withId(R.id.task_detail_complete_checkbox)).check(matches(isChecked()))
    }

এই শেষ পদক্ষেপে আপনি কীভাবে নেভিগেশন উপাদানটি পরীক্ষা করবেন, একটি মক নামে পরিচিত একটি ভিন্ন ধরণের পরীক্ষার ডাবল এবং পরীক্ষার লাইব্রেরি মকিটো ব্যবহার করে শিখবেন।

এই কোডল্যাবটিতে আপনি একটি নকল নামে একটি পরীক্ষা ডাবল ব্যবহার করেছেন। জালগুলি বিভিন্ন ধরণের পরীক্ষার ডাবলগুলির মধ্যে একটি। নেভিগেশন উপাদানটি পরীক্ষা করার জন্য আপনার কোন পরীক্ষার ডাবল ব্যবহার করা উচিত?

নেভিগেশন কীভাবে ঘটে সে সম্পর্কে চিন্তা করুন। কোনও টাস্ক বিশদ স্ক্রিনে নেভিগেট করতে TasksFragment একটি কাজ টিপুন কল্পনা করুন।

TasksFragment এখানে কোড রয়েছে যা কোনও টাস্ক বিশদ স্ক্রিনে নেভিগেট করে যখন এটি চাপ দেওয়া হয়।

টাস্কসফ্র্যাগমেন্ট.কেটি

private fun openTaskDetails(taskId: String) {
    val action = TasksFragmentDirections.actionTasksFragmentToTaskDetailFragment(taskId)
    findNavController().navigate(action)
}


navigate পদ্ধতিতে কল করার কারণে নেভিগেশন ঘটে। আপনার যদি কোনও দৃ statement ় বিবৃতি লেখার প্রয়োজন হয় তবে আপনি TaskDetailFragment নেভিগেট করেছেন কিনা তা পরীক্ষা করার কোনও সহজ উপায় নেই। নেভিগেট করা একটি জটিল ক্রিয়া যা TaskDetailFragment সূচনা করার বাইরে পরিষ্কার আউটপুট বা রাষ্ট্রীয় পরিবর্তনের ফলাফল করে না।

আপনি যা দৃ sert ় করতে পারেন তা হ'ল navigate পদ্ধতিটি সঠিক ক্রিয়া প্যারামিটারের সাথে কল করা হয়েছিল। এটি ঠিক একটি মক টেস্ট ডাবল করে - এটি নির্দিষ্ট পদ্ধতি বলা হয়েছিল কিনা তা পরীক্ষা করে।

মকিটো পরীক্ষা দ্বিগুণ করার জন্য একটি কাঠামো। মক শব্দটি এপিআই এবং নামে ব্যবহৃত হলেও এটি কেবল মক তৈরির জন্য নয় । এটি স্টাব এবং গুপ্তচরও তৈরি করতে পারে।

আপনি মকিটো ব্যবহার করবেন একটি মক NavigationController তৈরি করতে যা ন্যাভিগেট পদ্ধতিটি সঠিকভাবে বলা হয়েছিল তা জোর দিতে পারে।

পদক্ষেপ 1। গ্রেডল নির্ভরতা যুক্ত করুন

  1. গ্রেডল নির্ভরতা যুক্ত করুন

অ্যাপ্লিকেশন/বিল্ড.গ্রাডল

    // Dependencies for Android instrumented unit tests
    androidTestImplementation "org.mockito:mockito-core:$mockitoVersion"

    androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito:$dexMakerVersion" 

    androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"



  • org.mockito:mockito-core -এটি মকিটো নির্ভরতা।
  • dexmaker-mockito -এই লাইব্রেরিটি অ্যান্ড্রয়েড প্রকল্পে মকিটো ব্যবহার করতে হবে। মকিটো রানটাইমে ক্লাস তৈরি করতে হবে। অ্যান্ড্রয়েডে, এটি ডেক্স বাইট কোড ব্যবহার করে করা হয় এবং তাই এই গ্রন্থাগারটি মকিটোকে অ্যান্ড্রয়েডে রানটাইমের সময় অবজেক্ট তৈরি করতে সক্ষম করে।
  • androidx.test.espresso:espresso-contrib -এই গ্রন্থাগারটি বাহ্যিক অবদান (অতএব নাম) দিয়ে গঠিত যা আরও উন্নত দর্শনের জন্য টেস্টিং কোড রয়েছে, যেমন DatePicker এবং RecyclerView । এটিতে অ্যাক্সেসিবিলিটি চেক এবং ক্লাস নামক CountingIdlingResource রয়েছে যা পরে আচ্ছাদিত।

পদক্ষেপ 2। টাস্কসফ্রেগমেন্টস্টেস্ট তৈরি করুন

  1. TasksFragment খুলুন।
  2. TasksFragment শ্রেণীর নামটিতে ডান ক্লিক করুন এবং তারপরে পরীক্ষা করুন নির্বাচন করুন। অ্যান্ড্রয়েডটেস্ট উত্স সেটটিতে একটি পরীক্ষা তৈরি করুন।
  3. এই কোডটি TasksFragmentTest অনুলিপি করুন।

টাস্কসফ্রেগমেন্ট টেস্ট.কেটি

@RunWith(AndroidJUnit4::class)
@MediumTest
@ExperimentalCoroutinesApi
class TasksFragmentTest {

    private lateinit var repository: TasksRepository

    @Before
    fun initRepository() {
        repository = FakeAndroidTestRepository()
        ServiceLocator.tasksRepository = repository
    }

    @After
    fun cleanupDb() = runBlockingTest {
        ServiceLocator.resetRepository()
    }

}

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

  1. পরীক্ষাটি ক্লিক clickTask_navigateToDetailFragmentOne

টাস্কসফ্রেগমেন্ট টেস্ট.কেটি

    @Test
    fun clickTask_navigateToDetailFragmentOne() = runBlockingTest {
        repository.saveTask(Task("TITLE1", "DESCRIPTION1", false, "id1"))
        repository.saveTask(Task("TITLE2", "DESCRIPTION2", true, "id2"))

        // GIVEN - On the home screen
        val scenario = launchFragmentInContainer<TasksFragment>(Bundle(), R.style.AppTheme)
        
    }
  1. একটি মক তৈরি করতে মকিটোর mock ফাংশন ব্যবহার করুন।

টাস্কসফ্রেগমেন্ট টেস্ট.কেটি

 val navController = mock(NavController::class.java)

মকিটোতে উপহাস করার জন্য, আপনি যে ক্লাসে মক করতে চান সে ক্লাসে পাস করুন।

এরপরে, আপনাকে আপনার NavController খণ্ডটির সাথে যুক্ত করতে হবে। onFragment আপনাকে খণ্ডে নিজেই পদ্ধতিগুলি কল করতে দেয়।

  1. আপনার নতুন মককে খণ্ডের NavController করুন।
scenario.onFragment {
    Navigation.setViewNavController(it.view!!, navController)
}
  1. "শিরোনাম 1" পাঠ্য রয়েছে এমন RecyclerView আইটেমটিতে ক্লিক করতে কোডটি যুক্ত করুন।
// WHEN - Click on the first list item
        onView(withId(R.id.tasks_list))
            .perform(RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
                hasDescendant(withText("TITLE1")), click()))

RecyclerViewActions espresso-contrib লাইব্রেরির একটি অংশ এবং আপনাকে একটি পুনর্ব্যবহারের উপর এস্প্রেসো ক্রিয়া সম্পাদন করতে দেয়।

  1. সঠিক যুক্তি সহ navigate ডাকা হয়েছিল তা যাচাই করুন।
// THEN - Verify that we navigate to the first detail screen
verify(navController).navigate(
    TasksFragmentDirections.actionTasksFragmentToTaskDetailFragment( "id1")

মকিটোর verify পদ্ধতিটি হ'ল এটি এটিকে একটি মক করে তোলে - আপনি প্যারামিটার সহ একটি নির্দিষ্ট পদ্ধতি ( navigate ) নামে পরিচিত মকড navController নিশ্চিত করতে সক্ষম হন ("আইডি 1" এর আইডি সহ actionTasksFragmentToTaskDetailFragment )।

সম্পূর্ণ পরীক্ষাটি এর মতো দেখাচ্ছে:

@Test
fun clickTask_navigateToDetailFragmentOne() = runBlockingTest {
    repository.saveTask(Task("TITLE1", "DESCRIPTION1", false, "id1"))
    repository.saveTask(Task("TITLE2", "DESCRIPTION2", true, "id2"))

    // GIVEN - On the home screen
    val scenario = launchFragmentInContainer<TasksFragment>(Bundle(), R.style.AppTheme)
    
                val navController = mock(NavController::class.java)
    scenario.onFragment {
        Navigation.setViewNavController(it.view!!, navController)
    }

    // WHEN - Click on the first list item
    onView(withId(R.id.tasks_list))
        .perform(RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
            hasDescendant(withText("TITLE1")), click()))


    // THEN - Verify that we navigate to the first detail screen
    verify(navController).navigate(
        TasksFragmentDirections.actionTasksFragmentToTaskDetailFragment( "id1")
    )
}
  1. আপনার পরীক্ষা চালান!

সংক্ষেপে, নেভিগেশন পরীক্ষা করতে আপনি পারেন:

  1. একটি NavController মক তৈরি করতে মকিটো ব্যবহার করুন।
  2. টুকরো টুকরো টুকরো NavController টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো
  3. যাচাই করুন যে ন্যাভিগেটকে সঠিক ক্রিয়া এবং প্যারামিটার (গুলি) দিয়ে ডাকা হয়েছিল।

পদক্ষেপ 3। al চ্ছিক, ক্লিক করুন অ্যাডডটাস্কবটন_নাভিগেটেটডডেডিটফ্র্যাগমেন্ট লিখুন

আপনি নিজেই কোনও নেভিগেশন পরীক্ষা লিখতে পারেন কিনা তা দেখতে, এই কাজটি ব্যবহার করে দেখুন।

  1. টেস্টটি লিখুন clickAddTaskButton_navigateToAddEditFragment যা পরীক্ষা করে যে আপনি যদি + ফ্যাব ক্লিক করেন তবে আপনি AddEditTaskFragment নেভিগেট করুন।

উত্তর নিচে দেওয়া হল।

টাস্কসফ্রেগমেন্ট টেস্ট.কেটি

    @Test
    fun clickAddTaskButton_navigateToAddEditFragment() {
        // GIVEN - On the home screen
        val scenario = launchFragmentInContainer<TasksFragment>(Bundle(), R.style.AppTheme)
        val navController = mock(NavController::class.java)
        scenario.onFragment {
            Navigation.setViewNavController(it.view!!, navController)
        }

        // WHEN - Click on the "+" button
        onView(withId(R.id.add_task_fab)).perform(click())

        // THEN - Verify that we navigate to the add screen
        verify(navController).navigate(
            TasksFragmentDirections.actionTasksFragmentToAddEditTaskFragment(
                null, getApplicationContext<Context>().getString(R.string.add_task)
            )
        )
    }

আপনি শুরু করা কোড এবং চূড়ান্ত কোডের মধ্যে একটি পার্থক্য দেখতে এখানে ক্লিক করুন।

সমাপ্ত কোডেল্যাবের জন্য কোডটি ডাউনলোড করতে, আপনি নীচে গিট কমান্ডটি ব্যবহার করতে পারেন:

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


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

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

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

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

উদাসী কোর্স:

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

ভিডিও:

অন্যান্য:

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