مقدمه ای بر تست UI برنامه های اندرویدی با Espresso

اسپرسو espresso انسانها مستعد اشتباه هستند و این ماهیت انسان ها باعث ایجاد نقص در کارکرد ، باگ ، آسیب های امنیتی و ... در نرم افزار میشود.پس از مدتی در توسعه نرم افزار متوجه نیاز به تست برنامه را حس میکنید. این نیاز زمانی بیشتر خود را نشان میدهد که در حال توسعه یک نرم افزار باشید و به صورت مداوم نیاز به تغییر کد های گذشته و افزودن قابلیت های جدید به پروژه باشد. اما تست نویسی فقط مربوط به پروژه های بزرگ نیست و پیشنهاد میشود در تمامی پرژه ها تست نوشته شود.تست منجر به شکست می شود، و شکست منجر به درکبنابر این قبل از ارائه نرم افزار خود به دیگران آن را تست کنید. انواع تست در اندرویدتست واحد | Unit Tests تست ابزاری | Instrumentation Testing تست در اندرویدتست واحد | Unit Tests :آزمایش کردن تمامی متد ها، بخش های (واحد های ) برنامه . به صورتی که پارامتر X را به یک واحد میدهیم و باید خروجی Y را از آن دریافت کنیم در غیره این صورت برنامه با خطا مواجه شده است.این نوع تست به صورت محلی بر روی JVM اجرا میشود و نیازی به اجرا بر روی دستگاه یا شبیه ساز اندرویدی نیست. تست ابزاری | Instrumentation Testing : ما در این مقاله بر روی این نوع از تست تمرکز میکنیم. Espresso یک Frameworks جهت تست خودکار Ui اپلیکیشن های اندرویدی است که توسط گوگل در حال توسعه میباشد.از جمله Frameworks های مشابه میتوان به Robolectric اشاره کرد.شروع کار با Espresso محیط آزمایش را تنظیم کنید برای جلوگیری از ایجاد اختلال در تست ، به شدت توصیه می کنیم که انیمیشن های دستگاه مورد استفاده برای آزمایش را در مسیر گفته شده غیرفعال کنید. در این مسیر Settings > Developer options تنظیمات زیر را غیرفعال کنید:Window animation scaleTransition animation scaleAnimator duration scaleاضافه کردن کتابخانه به Gradle کتابخانه های زیر را به app/build.gradle اضافه کنید.androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.2-alpha01' androidTestImplementation 'androidx.test:runner:1.1.2-alpha01' androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test:rules:1.1.1'و همپنین :testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"نتیجه به شکل زیر است :برای مطالعه بیشتر و دریافت آخرین ورژن به این آدرس مراجعه نمایید .ایجاد کلاس تست : برای شروع در مسیر زیر یک کلاس جدید ایجاد کنید (به صورت مثال یا نام MainActivityTest)module-name/src/androidTest/java/سپس در بالای کلاس @RunWith(AndroidJUnit4.class) را بنویسید. دلیل نوشتن این annotation آن است که در زمان اجرای تست ، هر کلاسی که دارای این annotation باشد به عنوان کلاس حاوی کد های تست شناسایی و پردازش میشود. معرفی اکتیویتی :اکنون برای معرفی اکتیویتی مورد نظر برای اجرا از annotation @Rule استفاده میکنیم.کد کلاس MainActivityTest ما تا اینجای کار به شکل زیر است :@RunWith(AndroidJUnit4.class) public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> activityActivityTestRule = new ActivityTestRule<>(MainActivity.class); }به طور کلی در زمان اجرای تست 6 نوع annotation داریم که در تصویر زیر ترتیب اجرای آن ها را میبینیدکاربرد انوتیشن ها در تست نمودار زیر تصویر جالبی از چرخه ی اکتیویتی و ترتیب فراخوانی annotation ها را می بینید1- شناسایی ویو ها در صفحه به کمک ViewMatcher :اسپرسو برای شناسای ویو ها در صفحه از کلاس ViewMatcher کمک میگیرد :ViewInteraction onView (Matcher<View> viewMatcher)به عنوان مثال ما در اکتیویتی main خود یک دکمه (android:id="@+id/button") تعریف کرده ایم . اسپرسو برای یافتن این ویو در صفحه چندین راه را ارائه کرده است. قطعه کد زیر ویو را به کمک id آن در صفحه شناسایی میکند.onView(withId(R.id.button));در مثال زیر همان دکمه را به کمک متن که روی آن ست شده پیدا میکنیم onView(withText("تایید"));سایر ViewMatcher ها را در تصویر زیر میبینید که هر کدام خاصیت مربوط به خود را داردند.ViewMatcher 2- اجرای Action های مختلف بر روی View ها به کمک perform:پس از پیدا کردن View ی مورد نظر در صفحه شما میتوانید اکشن های مختلفی روی آن ها انجام دهید.(click clearText , doubleClick , scrollTo)در مثال زیر میخواهیم روی دکمه ای که در مرحله قبل شناسایی کردیم کلیک انجام دهیم :onView(withId(R.id.button)).perform(click()); در مثال دیگری میخواهیم متنی را روی EditText بنویسیم :onView(withId(R.id.editText)).perform(typeText("متن آزمایشی"));تصویر زیر سایر action ها را مشاهده میکنید.3- بررسی ViewAssertions ها :پس از انجام اکشن های مختلف روی view ها شما نیاز دارید که بررسی کنید این اکشن باعث جه تغییری شده. به عنوان مثال بررسی کنیم آیا EditText خالی است ؟onView(withId(R.id.editText))//شناسای ویو .check(matches(withText("")));//بررسی این که آیا خالی است؟ViewAssertions 4- اجرای تست و مشاهده نتیجه:اجرای تستنتیجه تستمثال ساده :سناریو به این شکل است که یک متن آزمایشی را تایپ میکنیم . متن تایپ شده بعد از کلیک روی Button باید بر روی Text view نمایش داده شود.در نهایت بررسی میکنیم آیا متن نمایش داده شده همان متن تایپ شده است یا تست با شکست مواجه شده.کد کلاس اکتیویتی : public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EditText editText = findViewById(R.id.editText); TextView textView = findViewById(R.id.textView); Button button = findViewById(R.id.button); button.setListener(v -> { textView.setText(editText.getText().toString()); }); } }کد کلاس تست :@RunWith(AndroidJUnit4.class) public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> activityActivityTestRule = new ActivityTestRule<>(MainActivity.class);//معرفی اکتیویتی لانچر @Test public void TestAutoComplete() { String hello = "hello world"; onView(withId(R.id.editText))//شناسای ویو .perform(typeText(hello));//تایپ کردن متن onView(withId(R.id.button))//شناسای ویو .perform(click());//کلیلک روی دکمه onView(withId(R.id.textView))//شناسای ویو .check(matches(withText(hello)));//بررسی مقدار نمایش داده شده } }