البرنامج التعليمي لاختبار Android: اختبار الوحدة مثل True Green Droid
نشرت: 2022-03-11بصفتنا مطوري تطبيقات ذوي خبرة ، مع نضج التطبيقات التي نطورها ، نشعر بأن الوقت قد حان لبدء الاختبار. غالبًا ما تشير قواعد العمل إلى أن النظام يجب أن يوفر الاستقرار خلال الإصدارات المختلفة. نريد أيضًا بشكل مثالي أتمتة عملية الإنشاء ونشر التطبيق تلقائيًا. لهذا ، نحتاج إلى أدوات اختبار Adnroid في مكانها الصحيح لضمان عمل الإنشاء كما هو متوقع.
يمكن أن توفر الاختبارات مستوى إضافيًا من الثقة حول الأشياء التي نبنيها. من الصعب (إن لم يكن من المستحيل) بناء منتج مثالي خالٍ من الأخطاء. لذلك ، سيكون هدفنا هو تحسين احتمالات نجاحنا في السوق من خلال إعداد مجموعة اختبار ستكتشف بسرعة الأخطاء التي تم إدخالها حديثًا في تطبيقنا.
عندما يتعلق الأمر بنظام Android والأنظمة الأساسية للجوّال المختلفة بشكل عام ، يمكن أن يمثل اختبار التطبيقات تحديًا. غالبًا ما يبدو إجراء اختبارات الوحدة والمبادئ التالية للتطوير المدفوع بالاختبار أو ما شابه ذلك غير بديهي ، على الأقل. ومع ذلك ، فإن الاختبار مهم ، ولا ينبغي اعتباره أمرًا مفروغًا منه أو تجاهله. ناقش ديفيد وكينت ومارتن مزايا وعيوب الاختبار في سلسلة من المحادثات فيما بينهم جمعت في مقال بعنوان "هل ماتت TDD؟". يمكنك أيضًا العثور على محادثات الفيديو الفعلية هناك والحصول على مزيد من الأفكار إذا كان الاختبار يناسب عملية التطوير لديك وإلى أي مدى يمكنك دمجها ، بدءًا من الآن.
في هذا البرنامج التعليمي لاختبار Android ، سأوجهك خلال اختبار الوحدة والقبول والانحدار على Android. سنركز على تجريد وحدة الاختبارات على Android ، متبوعة بأمثلة لاختبار القبول ، مع التركيز على جعل العملية سريعة وبسيطة قدر الإمكان لتقصير دورات التغذية الراجعة للمطورين - ضمان الجودة.
هل يجب أن أقرأه؟
سيستكشف هذا البرنامج التعليمي الاحتمالات المختلفة عندما يتعلق الأمر باختبار تطبيقات Android. يمكن للمطورين أو مديري المشاريع الذين يرغبون في فهم أفضل لإمكانيات الاختبار الحالية لمنصة Android أن يقرروا استخدام هذا البرنامج التعليمي إذا كانوا يريدون اتباع أي من الأساليب المذكورة في هذه المقالة. ومع ذلك ، هذه ليست رصاصة فضية ، حيث أن المناقشة التي ينطوي عليها مثل هذا الموضوع تختلف بطبيعتها من منتج إلى منتج جنبًا إلى جنب مع المواعيد النهائية ، وجودة التعليمات البرمجية الأساسية ، ومستوى اقتران النظام ، وتفضيل المطور في تصميم الهندسة المعمارية ، والعمر المتوقع للميزة إلى اختبار ، إلخ.
التفكير في الوحدات: اختبار Android
من الناحية المثالية ، نريد اختبار وحدة / مكون منطقي للهندسة المعمارية بشكل مستقل. بهذه الطريقة يمكننا أن نضمن أن المكون الخاص بنا يعمل بشكل صحيح لمجموعة المدخلات التي نتوقعها. يمكن الاستهزاء بالتبعية ، الأمر الذي سيمكننا من كتابة اختبارات يتم تنفيذها بسرعة. علاوة على ذلك ، سنكون قادرين على محاكاة حالات النظام المختلفة بناءً على المدخلات المقدمة للاختبار ، والتي تغطي الحالات الغريبة في العملية.
الهدف من اختبار وحدة Android هو عزل كل جزء من البرنامج وإظهار صحة الأجزاء الفردية. يوفر اختبار الوحدة عقدًا صارمًا ومكتوبًا يجب أن تفي به قطعة الكود. نتيجة لذلك ، فإنه يوفر العديد من الفوائد. —ويكيبيديا
روبولكتريك
Robolectric هو إطار عمل لاختبار وحدة Android يسمح لك بإجراء اختبارات داخل JVM على محطة العمل الخاصة بالتطوير. يعيد Robolectric كتابة فئات Android SDK أثناء تحميلها ويجعل من الممكن تشغيلها على JVM عادي ، مما يؤدي إلى أوقات اختبار سريعة. علاوة على ذلك ، فإنه يتعامل مع تضخم المشاهدات وتحميل الموارد والمزيد من الأشياء التي يتم تنفيذها في كود C الأصلي على أجهزة Android ، مما يجعل الحاجة إلى المحاكيات والأجهزة المادية لتشغيل الاختبارات الآلية أمرًا عفا عليه الزمن.
موكيتو
Mockito هو إطار عمل ساخر يمكننا من كتابة اختبارات نظيفة في جافا. إنه يبسط عملية إنشاء مضاعفات الاختبار (mocks) ، والتي تُستخدم لاستبدال التبعيات الأصلية للمكون / الوحدة المستخدمة في الإنتاج. تناقش إجابة StackOverflow الاختلافات بين mocks و stubs بعبارات بسيطة إلى حد ما يمكنك قراءتها لمعرفة المزيد.
// you can mock concrete classes, not only interfaces LinkedList mockedList = mock(LinkedList.class); // stubbing appears before the actual execution when(mockedList.get(0)).thenReturn("first"); // the following prints "first" System.out.println(mockedList.get(0)); // the following prints "null" because get(999) was not stubbed System.out.println(mockedList.get(999));
بالإضافة إلى ذلك ، باستخدام Mockito ، يمكننا التحقق مما إذا كان قد تم استدعاء طريقة:
// mock creation List mockedList = mock(List.class); // using mock object - it does not throw any "unexpected interaction" exception mockedList.add("one"); mockedList.clear(); // selective, explicit, highly readable verification verify(mockedList).add("one"); verify(mockedList).clear();
الآن ، نعلم أنه يمكننا تحديد أزواج الفعل والتفاعل التي تحدد ما يحدث بمجرد تنفيذ إجراء معين على العنصر / المكون الذي تم الاستهزاء به. لذلك ، يمكننا أن نسخر من وحدات كاملة لتطبيقنا ، ولكل حالة اختبار نجعل الوحدة النمطية التي تم الاستهزاء بها تتفاعل بطريقة مختلفة. ستعكس الطرق المختلفة الحالات المحتملة للمكون الذي تم اختباره وزوج المكون الذي تم الاستهزاء به.
وحدة التجارب
في هذا القسم ، سنفترض هندسة MVP (مقدم عرض النموذج). الأنشطة والأجزاء هي المشاهدات ، والنماذج هي طبقة المستودع للمكالمات إلى قاعدة البيانات أو الخدمات البعيدة ، والمقدم هو "العقل" الذي يربط كل هذه الأشياء معًا من خلال تنفيذ منطق محدد للتحكم في المشاهدات والنماذج وتدفق البيانات من خلال تطبيق.
مكونات الاستخلاص
استهزاء بالآراء والنماذج
في مثال اختبار Android هذا ، سوف نسخر من العروض والنماذج ومكونات المستودع ، وسنختبر مقدم العرض. هذا واحد من أصغر الاختبارات ، ويستهدف مكونًا واحدًا في الهندسة المعمارية. علاوة على ذلك ، سوف نستخدم طريقة stubbing لإعداد سلسلة تفاعلات مناسبة وقابلة للاختبار:
@RunWith(RobolectricTestRunner.class) @Config(manifest = "app/src/main/AndroidManifest.xml", emulateSdk = 18) public class FitnessListPresenterTest { private Calendar cal = Calendar.getInstance(); @Mock private IFitnessListModel model; @Mock private IFitnessListView view; private IFitnessListPresenter presenter; @Before public void setup() { MockitoAnnotations.initMocks(this); final FitnessEntry entryMock = mock(FitnessEntry.class); presenter = new FitnessListPresenter(view, model); /* Define the desired behaviour. Queuing the action in "doAnswer" for "when" is executed. Clear and synchronous way of setting reactions for actions (stubbing). */ doAnswer((new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ArrayList<FitnessEntry> items = new ArrayList<>(); items.add(entryMock); ((IFitnessListPresenterCallback) presenter).onFetchAllSuccess(items); return null; } })).when(model).fetchAllItems((IFitnessListPresenterCallback) presenter); } /** Verify if model.fetchItems was called once. Verify if view.onFetchSuccess is called once with the specified list of type FitnessEntry The concrete implementation of ((IFitnessListPresenterCallback) presenter).onFetchAllSuccess(items); calls the view.onFetchSuccess(...) method. This is why we verify that view.onFetchSuccess is called once. */ @Test public void testFetchAll() { presenter.fetchAllItems(false); // verify can be called only on mock objects verify(model, times(1)).fetchAllItems((IFitnessListPresenterCallback) presenter); verify(view, times(1)).onFetchSuccess(new ArrayList<>(anyListOf(FitnessEntry.class))); } }
السخرية من طبقة الشبكات العالمية باستخدام MockWebServer
غالبًا ما يكون من الملائم أن تكون قادرًا على السخرية من طبقة الشبكات العالمية. يتيح لنا MockWebServer ترتيب الردود على طلبات محددة ننفذها في اختباراتنا. يمنحنا هذا فرصة لمحاكاة الاستجابات الغامضة التي نتوقعها من الخادم ، ولكن ليس من السهل إعادة إنتاجها. يسمح لنا بضمان التغطية الكاملة أثناء كتابة القليل من التعليمات البرمجية الإضافية.
يوفر مستودع أكواد MockWebServer مثالًا رائعًا يمكنك الرجوع إليه لفهم هذه المكتبة بشكل أفضل.
زوجي الاختبار المخصص
يمكنك كتابة النموذج الخاص بك أو مكون المستجدات وحقنه في الاختبار من خلال توفير وحدة نمطية مختلفة للرسم البياني للكائن باستخدام Dagger (http://square.github.io/dagger/). لدينا خيار التحقق مما إذا كانت حالة العرض قد تم تحديثها بشكل صحيح بناءً على البيانات التي يوفرها مكون النموذج المزعج:
/** Custom mock model class */ public class FitnessListErrorTestModel extends FitnessListModel { // ... @Override public void fetchAllItems(IFitnessListPresenterCallback callback) { callback.onError(); } @Override public void fetchItemsInRange(final IFitnessListPresenterCallback callback, DateFilter filter) { callback.onError(); } }
@RunWith(RobolectricTestRunner.class) @Config(manifest = "app/src/main/AndroidManifest.xml", emulateSdk = 18) public class FitnessListPresenterDaggerTest { private FitnessActivity activity; private FitnessListFragment fitnessListFragment; @Before public void setup() { /* setupActivity runs the Activity lifecycle methods on the specified class */ activity = Robolectric.setupActivity(FitnessActivity.class); fitnessListFragment = activity.getFitnessListFragment(); /* Create the objectGraph with the TestModule */ ObjectGraph localGraph = ObjectGraph.create(TestModule.newInstance(fitnessListFragment)); /* Injection */ localGraph.inject(fitnessListFragment); localGraph.inject(fitnessListFragment.getPresenter()); } @Test public void testInteractorError() { fitnessListFragment.getPresenter().fetchAllItems(false); /* suppose that our view shows a Toast message with the specified text below when an error is reported, so we check for it. */ assertEquals(ShadowToast.getTextOfLatestToast(), "Something went wrong!"); } @Module( injects = { FitnessListFragment.class, FitnessListPresenter.class }, overrides = true, library = true ) static class TestModule { private IFitnessListView view; private TestModule(IFitnessListView view){ this.view = view; } public static TestModule newInstance(IFitnessListView view){ return new TestModule(view); } @Provides public IFitnessListInteractor provideFitnessListInteractor(){ return new FitnessListErrorTestModel(); } @Provides public IFitnessListPresenter provideFitnessPresenter(){ return new FitnessListPresenter(view); } } }
إجراء الاختبارات
بيئة تطوير أندرويد
يمكنك بسهولة النقر بزر الماوس الأيمن فوق فئة اختبار أو طريقة أو حزمة اختبار كاملة وتشغيل الاختبارات من مربع حوار الخيارات في IDE.
صالة
يؤدي تشغيل اختبارات تطبيقات Android من الجهاز إلى إنشاء تقارير للفئات التي تم اختبارها في مجلد "الإنشاء" للوحدة المستهدفة. أكثر من ذلك ، إذا كنت تخطط لإعداد عملية بناء مؤتمتة ، فستستخدم النهج الطرفي. باستخدام Gradle ، يمكنك تشغيل جميع اختبارات تصحيح الأخطاء عن طريق تنفيذ ما يلي:
gradle testDebug
الوصول إلى "اختبار" مجموعة المصدر من إصدار Android Studio
يوفر الإصدار 1.1 من Android Studio والمكوِّن الإضافي Android Gradle دعمًا لوحدة اختبار التعليمات البرمجية الخاصة بك. يمكنك معرفة المزيد من خلال قراءة الوثائق الممتازة الخاصة بهم. الميزة تجريبية ، ولكنها أيضًا تضمين رائع حيث يمكنك الآن التبديل بسهولة بين اختبارات الوحدة ومجموعات مصادر اختبار الأجهزة من IDE. يتصرف بنفس الطريقة كما لو كنت ستبدل النكهات في IDE.
تسهيل العملية
قد لا تكون كتابة اختبارات تطبيقات Android ممتعة مثل تطوير التطبيق الأصلي. ومن ثم ، فإن بعض النصائح حول كيفية تسهيل عملية كتابة الاختبارات وتجنب المشكلات الشائعة أثناء إعداد المشروع ستساعد كثيرًا.
AssertJ Android
AssertJ Android ، كما قد تكون خمنت من الاسم ، عبارة عن مجموعة من الوظائف المساعدة التي تم إنشاؤها مع وضع Android في الاعتبار. إنه امتداد لمكتبة AssertJ الشعبية. تتراوح الوظائف التي يوفرها AssertJ Android من التأكيدات البسيطة ، مثل "assertThat (view) .isGone ()" ، إلى أشياء معقدة مثل:

assertThat(layout).isVisible() .isVertical() .hasChildCount(4) .hasShowDividers(SHOW_DIVIDERS_MIDDLE)
مع AssertJ Android وإمكانية توسيعه ، نضمن لك نقطة انطلاق بسيطة وجيدة لكتابة الاختبارات لتطبيقات Android.
مسار Robolectric و Manifest
أثناء استخدام Robolectric ، قد تلاحظ أنه يتعين عليك تحديد موقع البيان ، وأن إصدار SDK مضبوط على 18. ويمكنك القيام بذلك عن طريق تضمين تعليق توضيحي "Config".
@Config(manifest = "app/src/main/AndroidManifest.xml", emulateSdk = 18)
يمكن أن يؤدي إجراء الاختبارات التي تتطلب Robolectric من الجهاز إلى ظهور تحديات جديدة. على سبيل المثال ، قد ترى استثناءات مثل "لم يتم تعيين السمة". إذا كانت الاختبارات يتم تنفيذها بشكل صحيح من IDE ، ولكن ليس من الجهاز الطرفي ، فقد تحاول تشغيلها من مسار في الجهاز حيث لا يمكن حل مسار البيان المحدد. قد لا تشير قيمة التكوين ذات الترميز الثابت لمسار البيان إلى الموقع الصحيح من نقطة تنفيذ الأمر. يمكن حل ذلك من خلال استخدام العدائين المخصصين:
public class RobolectricGradleTestRunner extends RobolectricTestRunner { public RobolectricGradleTestRunner(Class<?> testClass) throws InitializationError { super(testClass); } @Override protected AndroidManifest getAppManifest(Config config) { String appRoot = "../app/src/main/"; String manifestPath = appRoot + "AndroidManifest.xml"; String resDir = appRoot + "res"; String assetsDir = appRoot + "assets"; AndroidManifest manifest = createAppManifest(Fs.fileFromPath(manifestPath), Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir)); return manifest; } }
تكوين Gradle
يمكنك استخدام ما يلي لتكوين Gradle لاختبار الوحدة. قد تحتاج إلى تعديل أسماء التبعيات والإصدارات المطلوبة بناءً على احتياجات مشروعك.
// Robolectric testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.9.5' testCompile 'com.squareup.dagger:dagger:1.2.2' testProvided 'com.squareup.dagger:dagger-compiler:1.2.2' testCompile 'com.android.support:support-v4:21.0.+' testCompile 'com.android.support:appcompat-v7:21.0.3' testCompile('org.robolectric:robolectric:2.4') { exclude module: 'classworlds' exclude module: 'commons-logging' exclude module: 'httpclient' exclude module: 'maven-artifact' exclude module: 'maven-artifact-manager' exclude module: 'maven-error-diagnostics' exclude module: 'maven-model' exclude module: 'maven-project' exclude module: 'maven-settings' exclude module: 'plexus-container-default' exclude module: 'plexus-interpolation' exclude module: 'plexus-utils' exclude module: 'wagon-file' exclude module: 'wagon-http-lightweight' exclude module: 'wagon-provider-api' }
خدمات الروبوتات والتشغيل
إذا كنت تستخدم خدمات Google Play ، فسيتعين عليك إنشاء رقم ثابت خاص بك لإصدار Play Services حتى يعمل Robolectric بشكل صحيح في تكوين هذا التطبيق.
<meta-data android:name="com.google.android.gms.version" android:value="@integer/gms_version" tools:replace="android:value" />
التبعيات الروبوتية لدعم المكتبات
مشكلة اختبار أخرى مثيرة للاهتمام هي أن Robolectric غير قادر على الرجوع إلى مكتبات الدعم بشكل صحيح. الحل هو إضافة ملف "project.properties" إلى الوحدة النمطية حيث توجد الاختبارات. على سبيل المثال ، بالنسبة لمكتبتي Support-v4 و AppCompat ، يجب أن يحتوي الملف على:
android.library.reference.1=../../build/intermediates/exploded-aar/com.android.support/support-v4/21.0.3 android.library.reference.2=../../build/intermediates/exploded-aar/com.android.support/appcompat-v7/21.0.3
اختبار القبول / الانحدار
يعمل اختبار القبول / الانحدار على أتمتة جزء من الخطوة الأخيرة للاختبار على بيئة Android حقيقية بنسبة 100٪. لا نستخدم فئات أنظمة تشغيل Android التي تم الاستهزاء بها على هذا المستوى - يتم إجراء الاختبارات على أجهزة ومحاكيات حقيقية.
تجعل هذه الظروف العملية أكثر استقرارًا نظرًا لتنوع الأجهزة المادية وتكوينات المحاكي وحالات الجهاز ومجموعات الميزات لكل جهاز. علاوة على ذلك ، يعتمد بشكل كبير على إصدار نظام التشغيل وحجم شاشة الهاتف لتحديد كيفية عرض المحتوى.
يعد إنشاء الاختبار الصحيح الذي يمر على مجموعة واسعة من الأجهزة أمرًا معقدًا بعض الشيء ، ولكن كما هو الحال دائمًا يجب أن تحلم كثيرًا ولكن تبدأ صغيرًا. يعد إنشاء الاختبارات باستخدام Robotium عملية تكرارية. مع بعض الحيل ، يمكن تبسيطها كثيرًا.
روبوتيوم
Robotium هو إطار عمل آلي لاختبار Android مفتوح المصدر موجود منذ يناير 2010. ومن الجدير بالذكر أن Robotium هو حل مدفوع الأجر ، ولكنه يأتي مع إصدار تجريبي مجاني.
لتسريع عملية كتابة اختبارات Robotium ، سنبتعد عن كتابة الاختبار اليدوي إلى اختبار التسجيل. المفاضلة بين جودة الكود والسرعة. إذا كنت تجري تغييرات كبيرة على واجهة المستخدم الخاصة بك ، فستستفيد كثيرًا من نهج التسجيل التجريبي وستكون قادرًا على تسجيل الاختبارات الجديدة بسرعة.
Testdroid Recorder هو مسجل اختبار مجاني يقوم بإنشاء اختبارات Robotium حيث يسجل النقرات التي تقوم بها على واجهة المستخدم. يعد تثبيت الأداة أمرًا سهلاً للغاية ، كما هو موضح في وثائقهم المصحوبة بفيديو خطوة بخطوة.
نظرًا لأن Testdroid Recorder هو مكون إضافي من Eclipse ونحن نشير إلى Android Studio طوال هذه المقالة ، فمن المثالي أن يكون سببًا للقلق. ومع ذلك ، في هذه الحالة ، لا يمثل ذلك مشكلة ، حيث يمكنك استخدام المكون الإضافي مباشرة مع APK وتسجيل الاختبارات ضده.
بمجرد إنشاء الاختبارات ، يمكنك نسخها ولصقها في Android Studio ، جنبًا إلى جنب مع أي تبعية يتطلبها مسجل Testdroid ، وستكون جاهزًا للعمل. سيبدو الاختبار المسجل مثل الفصل أدناه:
public class LoginTest extends ActivityInstrumentationTestCase2<Activity> { private static final String LAUNCHER_ACTIVITY_CLASSNAME = "com.toptal.fitnesstracker.view.activity.SplashActivity"; private static Class<?> launchActivityClass; static { try { launchActivityClass = Class.forName(LAUNCHER_ACTIVITY_CLASSNAME); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } private ExtSolo solo; @SuppressWarnings("unchecked") public LoginTest() { super((Class<Activity>) launchActivityClass); } // executed before every test method @Override public void setUp() throws Exception { super.setUp(); solo = new ExtSolo(getInstrumentation(), getActivity(), this.getClass() .getCanonicalName(), getName()); } // executed after every test method @Override public void tearDown() throws Exception { solo.finishOpenedActivities(); solo.tearDown(); super.tearDown(); } public void testRecorded() throws Exception { try { assertTrue( "Wait for edit text (id: com.toptal.fitnesstracker.R.id.login_username_input) failed.", solo.waitForEditTextById( "com.toptal.fitnesstracker.R.id.login_username_input", 20000)); solo.enterText( (EditText) solo .findViewById("com.toptal.fitnesstracker.R.id.login_username_input"), "[email protected]"); solo.sendKey(ExtSolo.ENTER); solo.sleep(500); assertTrue( "Wait for edit text (id: com.toptal.fitnesstracker.R.id.login_password_input) failed.", solo.waitForEditTextById( "com.toptal.fitnesstracker.R.id.login_password_input", 20000)); solo.enterText( (EditText) solo .findViewById("com.toptal.fitnesstracker.R.id.login_password_input"), "123456"); solo.sendKey(ExtSolo.ENTER); solo.sleep(500); assertTrue( "Wait for button (id: com.toptal.fitnesstracker.R.id.parse_login_button) failed.", solo.waitForButtonById( "com.toptal.fitnesstracker.R.id.parse_login_button", 20000)); solo.clickOnButton((Button) solo .findViewById("com.toptal.fitnesstracker.R.id.parse_login_button")); assertTrue("Wait for text fitness list activity.", solo.waitForActivity(FitnessActivity.class)); assertTrue("Wait for text KM.", solo.waitForText("KM", 20000)); /* Custom class that enables proper clicking of ActionBar action items */ TestUtils.customClickOnView(solo, R.id.action_logout); solo.waitForDialogToOpen(); solo.waitForText("OK"); solo.clickOnText("OK"); assertTrue("waiting for ParseLoginActivity after logout", solo.waitForActivity(ParseLoginActivity.class)); assertTrue( "Wait for button (id: com.toptal.fitnesstracker.R.id.parse_login_button) failed.", solo.waitForButtonById( "com.toptal.fitnesstracker.R.id.parse_login_button", 20000)); } catch (AssertionFailedError e) { solo.fail( "com.example.android.apis.test.Test.testRecorded_scr_fail", e); throw e; } catch (Exception e) { solo.fail( "com.example.android.apis.test.Test.testRecorded_scr_fail", e); throw e; } } }
إذا نظرت عن كثب ، ستلاحظ مقدار الشفرة التي تكون مباشرة إلى حد ما.
عند تسجيل الاختبارات ، لا تندر في عبارات "الانتظار". انتظر ظهور الحوارات وظهور الأنشطة والنصوص. سيضمن هذا أن النشاط والتسلسل الهرمي للعرض جاهزان للتفاعل معه عند تنفيذ الإجراء على الشاشة الحالية. في نفس الوقت ، التقط لقطات شاشة. عادةً ما تكون الاختبارات الآلية غير مراقبة ، ولقطات الشاشة هي إحدى الطرق التي يمكنك من خلالها معرفة ما حدث بالفعل أثناء تلك الاختبارات.
سواء نجحت الاختبارات أو فشلت ، فإن التقارير هي أفضل صديق لك. يمكنك العثور عليها ضمن دليل البناء "module / build / outputs / reports":
من الناحية النظرية ، يمكن لفريق ضمان الجودة تسجيل الاختبارات وتحسينها. من خلال بذل الجهد في نموذج موحد لتحسين حالات الاختبار ، يمكن القيام بذلك. عندما تقوم عادة بتسجيل الاختبارات ، عليك دائمًا تعديل بعض الأشياء لجعلها تعمل بشكل لا تشوبه شائبة.
أخيرًا ، لتشغيل هذه الاختبارات من Android Studio ، يمكنك تحديدها وتشغيلها كما تفعل مع اختبارات الوحدة. من المحطة عبارة عن خط واحد:
gradle connectedAndroidTest
أداء الاختبار
يعد اختبار وحدة Android باستخدام Robolectric سريعًا للغاية ، لأنه يعمل مباشرة داخل JVM على جهازك. مقارنةً بذلك ، يعد اختبار القبول على المحاكيات والأجهزة المادية أبطأ كثيرًا. اعتمادًا على حجم التدفقات التي تختبرها ، يمكن أن يستغرق الأمر من بضع ثوانٍ إلى بضع دقائق لكل حالة اختبار. يجب استخدام مرحلة اختبار القبول كجزء من عملية إنشاء مؤتمتة على خادم تكامل مستمر.
يمكن تحسين السرعة بالتوازي على أجهزة متعددة. تحقق من هذه الأداة الرائعة من Jake Wharton والرجال في Square http://square.github.io/spoon/. لديها بعض التقارير الجيدة أيضا.
الوجبات الجاهزة
هناك مجموعة متنوعة من أدوات اختبار Android المتاحة ، ومع نضوج النظام البيئي ، ستصبح عملية إعداد بيئة قابلة للاختبار وكتابة الاختبارات أسهل. لا يزال هناك المزيد من التحديات التي يجب معالجتها ، ومع وجود مجتمع عريض من المطورين الذين يعملون على حل المشكلات اليومية ، هناك مجال كبير للمناقشات البناءة وردود الفعل السريعة.
استخدم الأساليب الموضحة في هذا البرنامج التعليمي لاختبار Android لإرشادك في مواجهة التحديات التي تنتظرك. إذا واجهتك مشكلات وعندما تواجهك ، فراجع هذه المقالة أو المراجع المرتبطة بالداخل للحصول على حلول للمشكلات المعروفة.
في منشور مستقبلي ، سنناقش الموازاة ، وبناء الأتمتة ، والتكامل المستمر ، وخطافات Github / BitBucket ، وإصدار القطع الأثرية ، وأفضل الممارسات لإدارة مشاريع تطبيقات الهاتف المحمول الضخمة بتعمق أكبر.