Flutter'da Unit Test Yazımı

Giriş

Flutter'un sağladığı 3 test tipi vardır. Bunlar;

  1. Unit Test (Unit test, tek bir fonksiyonu, metodu veya class'ı test eder.),
  2. Widget Test (Bir widget testi (diğer UI frameworklerinde bileşen/component testi olarak bilinir) tek bir widget'ı test eder.),
  3. Integration Test'tir (Bir entegrasyon testi, eksiksiz bir uygulamayı veya bir uygulamanın büyük bir bölümünü test eder.).

Güven seviyesi, bakım maliyeti, bağımlılıklar ve yürütme hızı bakımından farklılıkları da şu şekildedir.

Anatomy of Unit Testing

Bu bölümde Unit Test'lerin ne olduğu, özellikleri, yapısı ve daha bir çok özelliğini inceleyeceğiz. Hadi başlayalım!

İçindekiler

  1. Unit Test Nedir?
  2. Unit Testinin Anatomisi
  3. Neler Gerekli?
  4. Unit Test'i Çalıştırma
  5. Test Dosyası Oluşturma
  6. Test'e Başlangıç
  7. Unit Test'te Beklenen Sonuçların Kontrol Edilmesi
  8. Eşleştiriciler/Matchers Nedir?
  9. Unit Test'leri Gruplama
  10. Hata/Error veya İstisna/Exception Veren Kodu Test Etme

1. Unit Test Nedir?

2. Unit Testinin Anatomisi

Birim testleri genel olarak 3 aşamaya ayrılır.

Pre Test: Test edilecek kısım için gerekli olabilecek başlangıçların yapıldığı aşamadır. setUpAll ve setUp metotları kullanılarak gerçekleştirilir.

- setUp: Her test senaryosundan önce çalıştırılması gereken işlemleri içerir.
- setUpAll: Tüm test durumları yürütülmeden önce bir kez çalışır.

Test: Asıl testin yürütüldüğü test aşamsı burasıdır.

- test: Asıl test aşamasıdır.

Post Test: Mock değerleri sıfırlamak için kullanılan test sonrası aşamasıdır.

- tearDown: Her test senaryosundan sonra çalıştırılması gereken işlemleri içerir.
- tearDownAll: Tüm test durumları yürütüldükten sonra bir kez çalışır.

Anatomy of Unit Testing

3. Neler Gerekli?

test paketi, Unit testleri yazmak için temel frameworkü sağlar. flutter_test paketi ise, widget'ları da test etmenizi sağlayacak için ek araçlar sağlar.

Bundan dolayı test sayfanızda flutter_test paketi aşağıdaki gibi ekli olmalıdır.

import 'package:flutter_test/flutter_test.dart';

Bu paketi test sayfanızda kullanabilmek için de, pubspec.yaml dosyasında dev_dependencies altında flutter_test paketi eklenmiş olmalıdır. Flutter projesi oluşturulduğunda varsayılan olarak bu paket eklenmiş olarak gelmektedir.

4. Unit Test'i Çalıştırma

Testlerinizi favori IDE'niz üzerinden aşağıdaki gibi çalıştırabilirsiniz.

IntelliJ/Android Studio

  1. hesapla_test.dart dosyasını açın,
  2. Run menüsünü seçin,
  3. 'tests in hesapla_test.dart' seçeneğini tıklayın.

VSCode

  1. hesapla_test.dart dosyasını açın,
  2. Run menüsünü seçin,
  3. Start Debugging seçeneğini tıklayın.

Bir diğer seçenekte, komut satırı üzerinden çalıştırmaktır.

Flutter test ile ilgili ihtiyaç duyabileceğiniz tüm komutları

flutter test --help komutu ile öğrenebilirsiniz.

Örneğin;

Terminalden çalıştıracağınız flutter test komutu ile test klasörü içerisindeki tüm testleri koşturabilirsiniz.

Eğer belirli bir dosyayı test etmek istiyorsanız;

flutter test test/core/hesapla_test.dart

Projenizdeki Unit Test Coverage raporunu görmek istiyorsanız;

flutter test --coverage test komutunu kullanabilirsiniz.

Unit Test Coverage

Flutter, Coverage kapsama verilerini göstermek için lcov.info dosyasını kullanır. Komut satırından coverage alma komutunu çalıştırdığınıda proje ana dizini altında "coverage" klasörü ve onun altında "lcov.info" dosyası oluşur. Bu dosyayı kullanarak raporun HTML olarak çıktısını da oluşturmanız mümkün.

Bunu kullanmak için macOS'ta sisteminizde lcov (brew install lcov) kurulu olmalıdır. Daha sonra aşağıdaki komutu çalıştırabilirisiniz.

genhtml coverage/lcov.info -o coverage/html

Raporu komut satırından açmak için;

open coverage/html/index.html

Unit Test Coverage

5. Test Dosyası Oluşturma

Flutter'da tüm test dosyaları, projenizin altındaki test dizini altına yerleştirilmeli ve mutlaka _test.dart ile bitmelidir.

Test dosyalarınızı oluştururken, projenizin lib dizin yapısını kullanmak iyi bir alışkanlıktır. Böylece ilgili test dosyalarına bulmanız da kolaylaşır.

Test Files

6. Test'e Başlangıç

Bir test fonksiyonu Given, When, Then pattern adı verilen 3 temel bölüme ayrılır.

Test

Given: Sistemin başlangıç durumunu tanımlar.

When: Yapılacak aksiyonu tanımlamak için kullanılır. Yapılmak istenen asıl eylem, bu bölümde yazılır.

Then: Beklenen durumla gerçekleşen durumu karşılaştırdığımız bölümdür.

Test

7. Unit Test'te Beklenen Sonuçların Kontrol Edilmesi

Unit Test'lerdeki beklenen sonuçların karşılaştırması Given | When | Then pattern'inin Then adımında gerçekleşir.

Test

Örneğimizde expect metodu ile Hesapla class'ına ait topla metoduyla bir işlem gerçekleşmiş, bu işlemin sonunda elde edilen sonuç ile beklenen sonuç karşılaştırılmıştır. Eğer sonuç ve beklenen aynı ise test başarılı olacaktır.

Test

Test

Testin başarısız olma durumunda ise kullanıcıya ek bilgi sağlayabiliriz.

Bunun için örneğimizi aşağıdaki gibi güncelleyelim.

Test

Test

Yukarıda da görüldüğü gibi result değeri 5 iken, 6 ile karşılaştırıldığından dolayı test fail edecek ve reason bölümünde belirttiğimiz "Sonuçlar eşit değil." mesajını bize ek bilgi olarak gösterecektir. reason bölümünde belirttiğiniz hata mesajının yalnızca testin fail olması durumunda ortaya çıkacağını unutmayın.

Kontrol etmek için örneğimizi aşağıdaki gibi güncelleyelim.

Test

Test

Görüldüğü gibi test geçerli olduğu için reason mesajı görüntülenmedi.

Ancak testi geçerli kılmak için isNot ve equals isimli Eşleştirici/Matcher'ları kullanarak doğruladık.

8. Eşleştiriciler/Matchers Nedir?

Son örneğimizde isNot ve equal matcher'larını kullandığımızı belirttik. Bu iki matcher'ı kullanarak 5 ile 6'nın eşit olmadıklarını kontrol etmek istedik. Test yazımı sırasında da basit iki nesnenin karşılaştırılmasının ötesinde daha karmaşık doğrulama testlerine ihtiyaç olur. Tam da bu nokta da matcher'lar kullanılır.

Dart, test frameworkünde bulunan dahili bir Matcher kitaplığı sağlar. Tüm özelliklerine buradan göz atabilirsiniz.

Bunun yanında Streams ile çalışırken karmaşık doğrulama yapmak için bir StreamMatcher, kendi eşleştiricinizi geliştirmeniz gerekiyorsa, CustomMatcher adlı bir yardımcı program sınıfı mevcuttur.

9. Unit Test'leri Gruplama

Şimdiye kadarki örneğimizde tek bir metodun test edilmesi ile çalıştık. Birden çok test içeren bir test dosyasına sahip olmak oldukça yaygındır.

Buna göre test örneğimizi aşağıdaki gibi düzenleyerek kullanabiliriz.

Grup Test

10. Hata/Error veya İstisna/Exception Veren Kodu Test Etme

Bazen kodunuzun, beklenen veya geçersiz bir durumu hesaba katmak için yürütülmesi sırasında bir istisna atması gerekir.

Hesapla isimli class'ımızda bulunan "bol" fonksiyonunu kullanarak bunu sağlayabiliriz. Bunun için bu fonksiyonu düzenleyerek içerisinde bir Argument hatası fırlatalım.

Bol Function Test

Bol Function

Bol Function Test Fail

Görüldüğü üzere bu işlemi gerçekleştirdiğimizde testimiz doğru şekilde çalışıyor ancak fail alıyor. Bunun önüne geçip, hem hata bilgisini vermesi hem de testin pass olması için, gerçekleşen durumu anonim bir fonksiyon ile sarmalayacağız. Böylece fonksiyon kodu dahili bir try-catch bloğunda çalışabilecek ve hatayı matcher'ımız ile karşılaştırabilecektir.

Bunun için kodumuzu aşağıdaki gibi düzenleyerek, tekrar çalıştıralım.

Bol Anonim Function

Bol Anonim Function Test Pass