ساخت آزمون های واحد محلی

یک تست محلی به جای یک دستگاه یا شبیه ساز Android، مستقیماً در ایستگاه کاری خودتان اجرا می شود. به این ترتیب، از ماشین مجازی جاوا (JVM) محلی شما، به جای یک دستگاه اندرویدی برای اجرای آزمایش ها استفاده می کند. تست های محلی به شما امکان می دهند منطق برنامه خود را سریعتر ارزیابی کنید. با این حال، عدم امکان تعامل با فریم ورک اندروید، محدودیتی در انواع تست هایی که می توانید اجرا کنید ایجاد می کند.

تست واحد رفتار بخش کوچکی از کد، واحد تحت آزمایش را تأیید می‌کند. این کار را با اجرای آن کد و بررسی نتیجه انجام می دهد.

تست‌های واحد معمولاً ساده هستند، اما زمانی که واحد مورد آزمایش با در نظر گرفتن قابلیت آزمایش طراحی نشده باشد، راه‌اندازی آنها می‌تواند مشکل ساز باشد:

  • کدی که می‌خواهید تأیید کنید باید از طریق آزمایش قابل دسترسی باشد. به عنوان مثال، شما نمی توانید یک روش خصوصی را مستقیماً آزمایش کنید. در عوض، کلاس را با استفاده از API های عمومی آن تست می کنید.
  • برای اجرای آزمایش‌های واحد به‌صورت مجزا ، وابستگی‌های واحد تحت آزمایش باید با مؤلفه‌هایی که شما کنترل می‌کنید، مانند تقلبی یا سایر دوبل‌های آزمایشی جایگزین شوند. اگر کد شما به فریم ورک اندروید بستگی داشته باشد، این امر به ویژه مشکل ساز است.

برای آشنایی با استراتژی‌های رایج تست واحد در Android، چه چیزی را تست کنیم را بخوانید.

محل تست های محلی

به طور پیش فرض، فایل های منبع برای تست های واحد محلی در module-name/src/test/ قرار می گیرند. زمانی که با استفاده از Android Studio یک پروژه جدید ایجاد می کنید، این فهرست از قبل وجود دارد.

افزودن وابستگی های آزمایشی

همچنین باید وابستگی های آزمایشی را برای پروژه خود پیکربندی کنید تا از API های استاندارد ارائه شده توسط چارچوب تست 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() را تأیید کند، که یک روش درون برنامه است. اگر isValidEmail() نیز true را برگرداند تابع تست true را برمی گرداند.

کاتلین


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"))
  }

}

جاوا


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 شامل کتابخانه‌ای است که حاوی تمام APIهای چارچوب Android است، درست مطابق با نسخه مورد استفاده در پروژه شما. کتابخانه تمام متدها و کلاس‌های عمومی آن APIها را نگه می‌دارد، اما کد داخل متدها حذف شده است. اگر به هر یک از روش ها دسترسی داشته باشید، آزمون یک استثنا ایجاد می کند.

این اجازه می دهد تا تست های محلی هنگام ارجاع به کلاس ها در چارچوب Android مانند Context ساخته شوند. مهمتر از آن، به شما امکان می دهد از یک فریم ورک تمسخر آمیز با کلاس های اندروید استفاده کنید.

تمسخر وابستگی های اندروید

یک مشکل معمولی این است که بفهمیم یک کلاس از یک منبع رشته ای استفاده می کند. می توانید منابع رشته ای را با فراخوانی متد getString() در کلاس Context بدست آورید. با این حال، یک تست محلی نمی‌تواند Context یا هیچ یک از روش‌های آن استفاده کند زیرا به چارچوب Android تعلق دارند. در حالت ایده آل، فراخوانی getString() از کلاس خارج می شود، اما این همیشه عملی نیست. راه حل این است که یک mock یا یک Context ایجاد کنید که همیشه مقدار یکسانی را هنگام فراخوانی متد getString() آن برمی گرداند.

با کتابخانه Mockable Android و فریمورک‌های تمسخر آمیز مانند Mockito یا MockK ، می‌توانید رفتار مدل‌های کلاس‌های اندروید را در آزمون‌های واحد خود برنامه‌ریزی کنید.

برای افزودن یک شیء ساختگی به تست واحد محلی خود با استفاده از Mockito، این مدل برنامه نویسی را دنبال کنید:

  1. همانطور که در تنظیمات محیط آزمایشی توضیح داده شده است، وابستگی کتابخانه Mockito را در فایل build.gradle خود قرار دهید.
  2. در ابتدای تعریف کلاس تست واحد خود، حاشیه نویسی @RunWith(MockitoJUnitRunner.class) را اضافه کنید. این حاشیه‌نویسی به اجراکننده آزمایشی Mockito می‌گوید که تأیید کند که استفاده شما از چارچوب درست است و راه‌اندازی اولیه اشیاء ساختگی شما را ساده می‌کند.
  3. برای ایجاد یک شیء ساختگی برای وابستگی اندروید، حاشیه‌نویسی @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 Testing Codelab را امتحان کنید.

خطا: "روش ... مسخره نشد"

اگر بخواهید با Error: "Method ... not mocked .

اگر استثناهای پرتاب‌شده برای تست‌های شما مشکل‌ساز هستند، می‌توانید رفتار را تغییر دهید تا متدها بسته به نوع بازگشتی، صفر یا صفر را برگردانند. برای انجام این کار، پیکربندی زیر را در فایل build.gradle سطح بالای پروژه خود در Groovy اضافه کنید:

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