Muqaddima:

Ilgari men ishlab chiquvchi birlik testlarini faqat xatolarni aniqlash uchun yozadi deb o'ylardim, lekin mening fikrim uning fikrlaridan biri edi. Birlik testlarini yozish, birlik testi paytida xatolarni aniqlashga yordam berishi mumkin, ammo u boshqa muhim va foydali mahsulotlarni keltirishi mumkin. Bu erda men unchalik mashhur bo'lmagan, ammo muhim deb o'ylaydigan ba'zi afzalliklarni keltiraman.

Qisqacha ma'lum birlik sinov afzalliklari:

Birlik testlari sizning qo'lda testingizni kamaytiradi, siz muayyan stsenariylarni yaratishingiz, ishga tushirishingiz va qo'lda qilishingiz shart emas (mening androidni ishlab chiqish tajribamda vaqtimni 10 soniyadan 6 metrgacha behuda sarflagan). Sinov imkoniyati sizga konfiguratsiyani olib keladi va bu sizga soniyalar ichidaturli stsenariylarni sinab ko'rish imkonini beradi, shuning uchun nosozliklarni tuzatish va manba kodlarini o'zgartirish uchun vaqtni ancha tejaysiz. Shuningdek, siz backend, ma'lumotlar bazasi va fayl o'zgarishlarini qo'lda sinab ko'rishning nojo'ya ta'siridan xavfsizsiz ... masxara yoki xotiradagi ma'lumotlar bazasi (izolyatsiya qilingan). Birliklarni sinovdan o'tkazish orqali ishlab chiquvchilar o'zlari tomonidan tekshiriladigan (avtomatlashtirish) ko'plab testlarni bajarishi vatakrorlashi mumkin va ular istalgan vaqtda rejalashtirilishi mumkin. Birlik testlari sizga FUT (sinov qilinayotgan funktsiya) holati qandayligini aniqlashga yordam beradi, siz chiqarishdan va QA jarayonidan qutqaradigan birlik testlaridantezkor fikr-mulohaza olishingiz mumkin, chunki qaysi birlik testlari ekanligini ko'rasiz. o'zgarishlar bilan buzilgan. Shuningdek, bir qator muvaffaqiyatli sinovlarni ko'rish tasalli va taskin beradi.

Xulosa:
- Turli stsenariylarni qo'llab-quvvatlash
- Avtomatlashtirilgan test
- Takrorlanadigan test
- Izolyatsiya qilingan test
- Tez fikr-mulohaza

1-Tasdiqlanadigan hujjatlar:

Funktsiya funksiyalar va bayonotlarni tuzish qanday qilib istalgan funksionallikni keltirishini ko'rsatadi, ammo birlik testi berilgan holat bo'yicha FUT (sinov ostidagi funktsiya) natijasi nima ekanligini yoki ma'lumot berish orqali funktsiyani chaqirishning yon ta'sirini ko'rsatadi. Birlik testi funktsiyaning funksionalligini hujjatlashtirishi mumkin, chunki armatura, mashq va tasdiqlash ishdagi holat, ma'lumotlar, operatsiya va chiqish munosabatlarini taqdim etadi. Ma'lumotlar va konfiguratsiyalar holatni ko'rsatadi, mashqlar operatsiyaga ta'sir qiluvchini ko'rsatadi va tasdiqlash kutishlarni ko'rsatadi. Shuning uchun birlik testida nima va qaysi ma'lumotlar taqdim etilishi muhim.

Birlik testini funktsiyaning holat yoki ma'lumotni chiqishga qanday uzatayotganini ko'rsatadigan holat sifatida ko'rish mumkin yoki siz funktsiyani berilgan parametrlar bo'yicha chaqirish natijasi nima ekanligini ko'rasiz, shuning uchun birlik testi ma'lumotlar va funktsiyaning natijaga munosabatini taqdim etadi. . Quyidagi birlik testlariga qarang.

fun test_ab_1_2(){
  val result = ab(1, 2)
  assertTrue(result == 3)
}

fun test_ab_2_3(){
  val result = ab(2, 3)
  assertTrue(result == 5)
}

fun test_ab_3_2(){
  val result = ab(3, 2)
  assertTrue(result == 5)
}

Yuqoridagi funktsiyalarni ko'rib, siz ab funktsiyasi sum funksiyasiga ega deb o'ylaysiz, siz haqsiz, turli parametrlarga ega bo'lgan birlik testini ko'rib, biz funktsiya nima ekanligini umumiy ko'rinishga ega bo'lamiz, lekin uning nomi yolg'onchi bo'lishi mumkin.

fun test_sum(){
  //The function tell us if given 2, 3 then result must have 5
  val result  = sum(2, 3)
  assertTrue(result == 5)
}

Ab funktsiyasining nomini sumga o'zgartirish orqali o'quvchilar funksiya nima ekanligini tezroq tushunadilar.

Ko'proq, o'qilishi mumkin bo'lgan, yo'naltirilgan birlik testlariga ega bo'lish uchun testlar uchun ob'ekt onasi (test ma'lumotlarini yaratuvchilar, armatura ma'lumotlari generatori) namunasidan foydalanishni tavsiya qilaman, chunki misol nima muhim va nima emasligini ko'rsatishi mumkin. Ko'rsatilgan naqshlar ma'lumotlar rolining noaniqligini kamaytirishi mumkin. Quyidagi testga qarang.

fun test_isValidDeeplink(){
    val whiteList = listOf(
        "google.com", "amazon.com"
    )
    val deeplink = "amazon.com/orders"
    val actual = isValidDeeplink(deeplink, whiteList)
    assertTrue(actual)
}

Yangi o'quvchilar uchun yuqoridagi birlik testini ko'rish orqali quyidagi savollar tug'ilishi mumkin: Nima uchun URL manzillarida sxema yo'q? nega ular turli yo'llar bilan tugaydi? google va amazonning roli qanday? Natija yo'l tufayli to'g'rimi yoki faqat xost muhimmi? Sinovdan maqsadimizni aniqlash uchun nomlangan qiymat va birlik test nomidan foydalanishimiz mumkin:

fun test_isValidDeeplink_valid_deeplink_by_path(){
   val just_aUrl1 = "google.com/users"
   val just_aUrl2 = "amazon.com/orders"
   val whiteList = arrayListOf(justAUrl_1,just_aUrl2)
   val deeplink = "amazon.com/orders"
   val actual = isValidDeeplink(deeplink, whiteList)
   assertTrue(actual)
}

Yana bir misol: Quyidagi testni ko'rib, miyamda ba'zi savollar paydo bo'ladi, nima uchun joylashuvdan keyin 21 qiymatiga ega versiya mavjud? Nega Amazon? (va boshqalar)

fun test_replaceLocationInUrl_in_center_of_url() {
    val url = "amazone.com/location=#LOCMARK/version=21"
    val actual = replaceLocationInUrl(url, "40.67654")
    val expected = "amazone.com/location=xasdsd/version=21"
    assertThat(actual).isEqualTo(expected)
}

Ammo biz ma'noli o'zgaruvchilarni qo'shish va quyidagi kabi ba'zi ma'lumotlar generatorlaridan foydalanish orqali ma'lumotlar rolining noaniqligini kamaytirishimiz mumkin. Quyidagi kod faqat joylashuv qiymatini #LOCMARK ga almashtirishni ko'rsatadi, boshqa ma'lumotlar, masalan, aParam va locationValue muhim emas. Boshqa versiya soʻrovi parametri yoʻq, joylashuv qiymati va asosiy URL muhim emas.

fun test_replaceLocationInUrl_in_center_of_url() {
    val locationValue = aString()
    val aParam = "${aString()}=${aString()}"
    val url = "${aUrl()}/location=#LOCMARK/${aParam}"
    val actual = replaceLocationInUrl(url, locationValue)
    val expected = basicUrl.plus("/location=$locationValue")
    assertThat(actual).isEqualTo(expected)
}

Eslatma: Agar biror narsa ahamiyatsiz bo'lsa, ko'rinmaslik yaxshiroqdir. (XUnit test namunalari: Jerar Meszaros tomonidan test kodini qayta tiklash)

Abstraktsiyani oshirish orqali yaxshi hujjatlarni taqdim etish uchun birlik sinovlarida texnik narsalarni kamaytiring.

Birlik testini hujjat sifatida ko'rib chiqsak, biz hujjatning haqiqiy yoki noto'g'riligini aytadigan tasdiqlanadigan hujjatga ega bo'lishimiz mumkin. Birlik sinovi muvaffaqiyatsiz tugagach, bu nimadir noto'g'ri ekanligini bildiradi, funksiya yoki birlik sinovi.

Xulosa:

  • Birlik testi ma'lumotlar, mashqlar va chiqish o'rtasidagi munosabatni ko'rsatadi.
  • Misol sifatida birlik testini ko'rish mumkin.
  • Birlik testi FUT qanday ishlashini ko'rsatadi.
  • Bitta funktsiya uchun bir nechta birlik sinovlari turli reaktsiyalarni beradi.
  • Birlik testi funksionallik va hujjat o'rtasidagi ziddiyatlarni ko'rsatishi mumkin bo'lgan tasdiqlanadigan hujjat bo'lishi mumkin.

Siz "mening gist" da ba'zi ma'lumotlar generatori funktsiyalarini ko'rishingiz mumkin, bu sizga ko'proq yo'naltirilgan birlik testlarini yozishga yordam berishi mumkin.



2-Yoquvchi yon ta'sirlar:

Kodlar bir-biriga bog'liq, deyarli har bir kod ma'lumotlar yoki funktsiyalarga bog'liq, kichik o'zgarishlar ba'zi funktsiyalarni bekor qilishi mumkin. O'zgarishlar to'lqinli ta'sirga ega. Kichkina loyihada biz funktsiyalar va sinflarni yodlashimiz va o'zgarishlar yoki nojo'ya ta'sirlarni bashorat qilishimiz mumkin, lekin loyiha o'sib ulg'ayganida va bir necha kishi katta loyihada ishlaganda, siz o'zgarishlaringizni qo'lda ishlata olmaysiz va sinab ko'ra olmaysiz, chunki mahsulot katta va kichikdir. o'zgartirish katta ta'sir ko'rsatishi mumkin, siz QA jamoasiga versiyani yetkazib berishingiz va yuzaga kelishi mumkin bo'lgan nojo'ya ta'sirlarni bartaraf etish uchun qanday o'zgarishlar qilganingizni aytib berishingiz kerak. Bunday loyiha ustida ishlash dahshatli, qo'rqinchli va bunday jarayon rivojlanishni sekinlashtiradi. Funktsiyadagi kichik o'zgarishlarning nojo'ya ta'siri nima ekanligini kim biladi, men funktsiyadan foydalanish orqali ikki yoki uch darajadagi o'zgarishlarni bashorat qila olaman, lekin qancha qatlam yo'qolsa, bashoratimizda noaniqlik ko'proq bo'ladi.

Agar sizda ko'plab birlik sinovlari bo'lgan loyihangiz bo'lsa, siz o'zgartirishlaringizni qo'llashingiz mumkin, keyin siz ishga tushirishingiz va birlik testlari natijalarini ko'rishingiz mumkin. Bu sizga yangi o'zgarishlarga qarshi sinov stsenariylari uchun ishonch beradi va har bir kichik o'zgarish uchun qo'lda test o'tkazishingiz shart emas.

C,vaB funktsiyalarini qabul qiling, agar C B ga bog'liq bo'lsa, Bda muvaffaqiyatsiz bo'lish C funktsiyasida muvaffaqiyatsizlikka olib keladi, agar tasdiqlash chiqishda bo'lsa.
quyidagi misol, getLeapYearColor isLeapYearga bog'liq va tasdiqlash getLeapYearColor chiqishiga bog'liq. O'nlab birlik testlariga ega bo'lsak, getLeapYearColor muvaffaqiyatsiz tugadi, chunki isLeapYear muvaffaqiyatsiz tugadi, bu bizni xatoning asosiy sababiga olib borish uchun yaxshi ishoradir.

fun getLeapYearColor(date: Calendar): Int {
    val isLeapYear = date.isLeapYear(date.getYear())
    return if (isLeapYear) {
        Color.PURPLE
    } else {
        Color.BLACK
    }
}

fun test_getMonthColor_leapYear() {
    val date = Calendar.getInstance()
    date.setDate(1399, 1, 1)
    assertEquals(getLeapYearColor(date), Color.PURPLE)
}

Men bir voqeani eshitdim, video o'yinda ishlab chiquvchi o'zining ballistik raketasining algoritmini o'zgartirdi, keyin o'yinning asosiy menyusi ishlamay qoldi (halokatga uchradi), o'zgaruvchan zonani oldindan aytish juda qiyin.

3-qo'riqlash o'zgarishlari:

Birlik testlari funksiya yoki boshqa funktsiyalardagi yangi o'zgarishlar (qasddan yoki qasddan) tomonidan kiritilgan xatolardan kodlarni FUT xatti-harakati yoki chiqishini tasdiqlash orqali himoya qilishi mumkin.

Agar birlik testlari har bir o'zgarishdan so'ng amalga oshirilsa, ishlab chiquvchi o'zgarishlarga nisbatan ishonchni topadi, chunki ishlab chiquvchi FUT chiqishi yoki harakatini berilgan ma'lumotlar va kutilgan natija bilan himoya qilgan. Shubhasiz, agar funktsiyaning funksionalligi o'zgargan bo'lsa, unda birlik testi haqiqiy emas.

Keyingi testda 1400-2-1 1400-1-30 dan keyin bo'lishi kutilmoqda, agar isAfterDate false qaytarsa, birlik testi yuguruvchiga xabar berishi kerak.

fun Date.isAfterDate(date: BaseCalendar): Boolean

fun test_isAfterDate_isTrue() {
    val date = newCalendar(1400, 2, 1)
    assert(date.isAfterDate(newCalendar(1400, 1, 30)==true)
}

Har bir yangi ishga tushirilganda, birlik testi FUTning berilgan kutilgan darajada ishlashini tekshiradi. FUT funksionalligi va birlik testi kutilmalari o'rtasidagi har qanday ziddiyat haqida xabar berilishi kerak.

Quyidagi funktsiyani ko'rib chiqing. Ishlab chiqarish jarayonida ishlab chiquvchi vaqtinchalik userDidLogin qo‘ng‘irog‘iga (har qanday sababga ko‘ra) izoh berdi va u userDidLoginga izohni olib tashlashni unutib qo‘ydi, bu xato dasturni buzmaydi, lekin tahliliy tizimda ishlamay qoldiradi. ma'lumotlar.

class LoginFragment(
    private val eventLogger: EventLogger,
    private val userRepository: UserRepository
) {
    fun submitLogin(userName: String, password: String): User? {
        val user = userRepository.login(userName, password)
        if (user != null) {
            //eventLogger.userDidLogin()
        }
        return user
    }
}

Agar kodni o'zgartirsangiz va birlik testi muvaffaqiyatsiz tugadi, keyin ushbu birlik testini yangilash orqali siz o'zgarishlarni amalga oshirasiz/tasdiqlaysiz.

Birlik testlari, masalan, FUTda sodir bo'ladigan xatolarni aniqlashi mumkin.

fun test_login_userDidLogin_mustBeCalled_whenLoginIsSuccessful() {
    val eventLogger = mock(EventLogger::class.java)
    val userRepository = mock(UserRepository::class.java)
    `when`(userRepository.login(any(), any())).thenReturn(User())
    val loginFragment = LoginFragment(eventLogger, userRepository)
    val user = loginFragment.submitLogin(anyString(), anyString())
    verify(eventLogger, times(1)).userDidLogin()
}

4-SUT bo'yicha sinovchi nuqtai nazari:

Ko'pincha biz kodni loyihalashda biz funksionallikka erishamiz va bu qo'ng'iroq qiluvchining o'zini o'zi sozlashi uchun javobgardir, asosan mijoz ishlab chiquvchilari backenddan keladigan ma'lumotlar haqiqiy deb taxmin qilishadi va biz ularni shunchaki ko'rsatishimiz kerak ... Ammo birlik testida biz topamiz tester ko'rinishida, tester turli holatlar va stsenariylarda FUT bilan SUTni tasavvur qiladi.

Quyidagi kodlar oddiy stsenariyda ishlaydi va onViewCreate bir marta chaqiriladi.

class HomeFragment(private val viewModel: HomeViewModel) : Fragment() {
    private val productList = ArrayList<ProductData>()
    fun onViewCreate() {
        val products = viewModel.fetchProductList()
        productList.addAll(products)
        showProductList()
    }
    fun shownProductList() = productList
}

Ishlab chiqarish muhitida muammoli stsenariylar sodir bo'lmaydi, deb o'zimizni aldash oson, shuning uchun uni hal qilishning hojati yo'q. Ishlab chiqarishda dasturchi istalgan funksionallikka erishishi kerak, lekin sinovda tester dasturning funksionalligini turli parametrlar bilan sinab ko'rishi kerak, tester boshqa nuqtai nazarga ega va sinovchi funksiya turli parametrlar bilan chaqirilsa nima bo'lishini osongina so'raydi yoki Nima bo'ladi, agar bu funktsiya ikki marta chaqirilsa (OS yoki dastur tomonidan)

fun test_onViewCreate_calledTwice() {
    val viewModel = mock(HomeViewModel::class.java)
    val data = arrayListOf(ProductData(), ProductData())
    `when`(viewModel.fetchProductList()).thenReturn(data)
    val homeFragment = HomeFragment(viewModel)
    homeFragment.onViewCreate()
    homeFragment.onViewCreate()
    //this test will fails
    assert(homeFragment.shownProductList().size == 2)
}

Yana bir misol: Ilovada sana qatori orqa qismdan keladi va u yyyy-MM-dd oralig'ida shartnoma tuzadi. Dasturchi darhol kodga o'tadi.

fun parseDate(date: String): Date {
    return SimpleDateFormat("yyyy-MM-dd").parse(date)
}

Ammo tester funktsiyani quyidagi kabi boshqa sana formati qatori bilan sinab ko'radi:

fun test_parseDate() {
    val actual =  parseDate("2000/12/21")
    //assert....
}

Sinovchining nuqtai nazari bizni bir xillikdan xabardorlikka qaytaradi, hech bo'lmaganda ishlab chiquvchi, agar ushbu kirish kiritilsa yoki ishlab chiquvchi funktsiyani yaxshilashga qaror qilsa, muammo yuzaga kelishini biladi.

Oxir-oqibat:
Birlik testlari QA ishlarini olib tashlamaydi, lekin ular sizga yanada barqaror mahsulotni yetkazib berishga va vaqtingizni tejashga yordam beradi.

Agar sizda biron bir argument yoki post haqida sharhingiz bo'lsa yoki o'z fikringizni baham ko'rmoqchi bo'lsangiz, sharhlarda menga xabar bering.

O'qiganingiz uchun rahmat.