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

يُجري الاختبار المحلي مباشرةً على محطة العمل الخاصة بك، بدلاً من جهاز 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.

ولإجراء ذلك، أنشئ فئة تحتوي على طريقة اختبار واحدة أو أكثر، وعادةً في module-name/src/test/ تبدأ طريقة اختبار بالتعليق التوضيحي @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، أو الحقيقة: المقتطف أعلاه هو مثال على كيفية استخدام junit.Assert

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

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

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

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

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

من خلال مكتبة Mockable Android وأطر العمل، مثل 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 API. المرجع والفئة SharedPreferencesHelperTest في رمز نموذجي يمكنك أيضًا تجربة الدرس التطبيقي حول الترميز الخاص باختبار Android.

خطأ: "الطريقة ... لم يتم تقليدها"

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

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

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