إنشاء اختبارات الوحدات المحلية

يتم تنفيذ الاختبار الخارجي مباشرةً على محطة عملك، وليس على جهاز Android أو محاكي. ولذلك، يستخدم هذا الإصدار آلة Java الافتراضية (JVM) المحلية بدلاً من جهاز Android لإجراء الاختبارات. تتيح لك الاختبارات المحلية تقييم منطق تطبيقك بسرعة أكبر. ومع ذلك، فإن عدم القدرة على التفاعل مع يفرض إطار عمل Android قيودًا على أنواع الاختبارات التي يمكنك إجراؤها.

يُحقِّق اختبار الوحدة من سلوك قسم صغير من الرمز، وهو الوحدة الخاضعة للاختبار. يقوم بذلك عن طريق تنفيذ هذه التعليمة البرمجية والتحقق من النتيجة.

تكون اختبارات الوحدة عادةً بسيطة، ولكن يمكن أن يتسبب إعدادها في مشاكل عندما لا يتم تصميم الوحدة التي يتم اختبارها مع مراعاة إمكانية اختبارها:

  • يجب أن يكون الرمز الذي تريد التحقّق منه متاحًا من خلال إجراء اختبار. على سبيل المثال، لا يمكنك اختبار طريقة خاصة مباشرةً. بدلاً من ذلك، يمكنك اختبار الفئة باستخدام واجهات برمجة التطبيقات المتاحة للجميع.
  • لإجراء اختبارات الوحدة في عزل، يجب استبدال التبعيات للوحدة التي يتم اختبارها بمكونات تتحكّم فيها، مثل العناصر المزيّفة أو النماذج المزدوجة للاختبار الأخرى. ويشكّل ذلك مشكلة كبيرة، خاصةً إذا كان الرمز يعتمد على إطار عمل Android.

للتعرّف على الاستراتيجيات الشائعة لاختبار الوحدات في Android، اقرأ الخطوات التالية الاختبار.

موقع الاختبارات المحلية

يتم تلقائيًا وضع الملفات المصدر لاختبارات الوحدات المحلية في module-name/src/test/ يكون هذا الدليل متوفّرًا عند إنشاء مشروع جديد باستخدام "استوديو Android".

إضافة تبعيات الاختبار

عليك أيضًا ضبط التبعيات المتعلقة بالاختبار لمشروعك لاستخدام واجهات برمجة التطبيقات العادية التي يوفّرها إطار عمل اختبار JUnit.

لإجراء ذلك، افتح ملف build.gradle في وحدة تطبيقك وحدِّد ما يلي. والمكتبات كتبعيات. استخدِم الدالة testImplementation للإشارة إلى أنّها تنطبق على مجموعة مصادر الاختبار المحلي، وليس على التطبيق:

dependencies {
  // Required -- JUnit 4 framework
  testImplementation "junit:junit:$jUnitVersion"
  // Optional -- Robolectric environment
  testImplementation "androidx.test:core:$androidXTestVersion"
  // Optional -- Mockito framework
  testImplementation "org.mockito:mockito-core:$mockitoVersion"
  // Optional -- mockito-kotlin
  testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
  // Optional -- Mockk framework
  testImplementation "io.mockk:mockk:$mockkVersion"
}

إنشاء صف لاختبار وحدة محلية

يمكنك كتابة فئة اختبار الوحدة على الجهاز المحلي كصفّ اختبار JUnit 4.

لإجراء ذلك، أنشئ فئة تحتوي على طريقة اختبار واحدة أو أكثر، عادةً في ملف برمجي ‎.java تبدأ طريقة الاختبار بتعليق توضيحي @Test وتحتوي على الرمز البرمجي لتنفيذ جانب واحد من المكوّن الذي تريد اختباره والتحقّق منه.

يوضح المثال التالي كيفية تنفيذ فئة اختبار وحدة محلية. تشير رسالة الأشكال البيانية تحاول طريقة الاختبار emailValidator_correctEmailSimple_returnsTrue()التحقق isValidEmail()، وهي طريقة داخل التطبيق. ستعرض دالة الاختبار true إذا كان isValidEmail() يعرض أيضًا true.

Kotlin


import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class EmailValidatorTest {
  @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"))
  }

}

Java


import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

class EmailValidatorTest {
  @Test
  public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"));
  }
}

يجب إنشاء اختبارات قابلة للقراءة تقيّم ما إذا كانت المكوّنات في تطبيقك تعرِض النتائج المتوقّعة. ننصحك باستخدام مكتبة تأكيدات مثل junit.Assert أو Hamcrest أو Truth. يوضّح المقتطف أعلاه كيفية استخدام junit.Assert.

مكتبة Android التي يمكن محاكاتها

عند تنفيذ اختبارات الوحدة على الجهاز، يتضمّن مكوّن Gradle الإضافي المتوافق مع Android مكتبة تحتوي على كل واجهات برمجة التطبيقات لإطار عمل Android، مع تعديلها لتتوافق مع الإصدار المستخدَم في مشروعك. تحتوي المكتبة على جميع الأساليب مختلفة من واجهات برمجة التطبيقات هذه، ولكن تمت إزالة التعليمات البرمجية داخل الطرق. في حال الوصول إلى أي من الطرق، يُرسِل الاختبار استثناءً.

يتيح ذلك إنشاء اختبارات محلية عند الإشارة إلى فئات في إطار عمل Android ، مثل Context. والأهم من ذلك، أنّه يسمح لك باستخدام إطار عمل لمحاكاة klassen مع فئات Android.

محاكاة لتبعيات Android

المشكلة النموذجية هي العثور على أن الفئة تستخدم مورد سلسلة. يمكنك الحصول على موارد السلاسل من خلال استدعاء طريقة getString() في فئة Context . ومع ذلك، لا يمكن أن يستخدم الاختبار المحلي Context أو أي من طرقه استنادًا إلى ينتمون إلى إطار عمل Android. من الأفضل إزالة الطلب إلى getString() من الصف، ولكن هذا ليس عمليًا في بعض الأحيان. يكمن الحل في إنشاء نموذج أو نموذج اختباري لواجهة Context يعرض دائمًا القيمة نفسها عند استدعاء getString().

باستخدام مكتبة Android Mockable وإطارات عمل المحاكاة مثل Mockito أو MockK، يمكنك برمجة سلوك النماذج المحاكية لفئات Android في اختبارات الوحدات.

لإضافة كائن وهمي إلى اختبار الوحدة المحلية باستخدام نموذج Mockito، يُرجى اتّباع الخطوات التالية: نموذج البرمجة:

  1. أدرِج مكتبة Mockito في ملف build.gradle، كما هو описан في إعداد بيئة الاختبار.
  2. في بداية تعريف فئة اختبار الوحدة، أضِف التعليق التوضيحي @RunWith(MockitoJUnitRunner.class). يطلب هذا التعليق التوضيحي من أداة بدء اختبارات Mockito التحقّق من صحة استخدامك للإطار العملي ومحاولة تبسيط عملية إعداد العناصر النموذجية.
  3. لإنشاء عنصر وهمي لتبعية Android، أضِف التعليق التوضيحي @Mock قبل إعلان الحقل.
  4. لمحاكاة سلوك التبعيات، يمكنك تحديد شرط و قيمة إرجاع عند استيفاء الشرط باستخدام الطريقتَين when() وthenReturn() .

يوضّح المثال التالي كيفية إنشاء اختبار وحدة يستخدِم عنصرًا اصطناعيًا Context في Kotlin تم إنشاؤه باستخدام Mockito-Kotlin.

import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {

  @Mock
  private lateinit var mockContext: Context

  @Test
  fun readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    val mockContext = mock<Context> {
        on { getString(R.string.name_label) } doReturn FAKE_STRING
    }

    val myObjectUnderTest = ClassUnderTest(mockContext)

    // ...when the string is returned from the object under test...
    val result: String = myObjectUnderTest.getName()

    // ...then the result should be the expected one.
    assertEquals(result, FAKE_STRING)
  }
}

لمزيد من المعلومات عن استخدام إطار عمل Mockito، اطّلِع على مرجع واجهة برمجة التطبيقات Mockito وفئته SharedPreferencesHelperTest في عيّنة الرمز البرمجي. جرِّب أيضًا الدرس التطبيقي حول اختبار Android.

.

الخطأ: "لم يتمّ محاكاة الطريقة ..."

تُعرِض مكتبة Mockable Android استثناءً إذا حاولت الوصول إلى أي من الطرق باستخدام الرسالة Error: "Method ... not mocked.

إذا كانت الاستثناءات البارزة تمثل مشاكل في اختباراتك، يمكنك تغيير بحيث تُرجع الطرق بدلاً من ذلك إما صفرًا أو صفرًا، اعتمادًا على نوع الإرجاع. لإجراء ذلك، أضِف الإعدادات التالية في ملفbuild.gradle على مستوى المشروع في Groovy:

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }