Flutter Entegrasyon Testi | Bölüm 2
Tags: flutter, dart, mobile, test
Published: 2022-06-25 17:27:00

✨ **Widget Tester Methodları:** Test ortamında widget'lar oluşturmayı ve bu widget'lar ile etkileşime girmeyi sağlar.

✨ **testWidgets() fonksiyonu**, her test case'i için otomatik olarak yeni bir WidgetTester oluşturur.

✨ **Finders:** Finder class'ları, test ortamında widget'ların aranmasını sağlar.

✨ **Matchers:** Widget'a özgü Matcher sabitleri, Finder'ın test ortamında bir widget'ı mı yoksa birden fazla widget'ı mı bulduğunu doğrulamaya yardımcı olur.

## testWidgets() fonksiyonu
Bir testi tanımlamak için flutter_test paketi tarafından sağlanan testWidgets() fonksiyonu kullanılır. testWidgets fonksiyonu, bir widget testi tanımlamanıza ve birlikte çalışmak için bir WidgetTester oluşturmanıza olanak tanır.

örnek:

```
void main() {
  testWidgets('test açıklaması', (tester) async {
// Test kodu buraya gelir.
  });
}
```

**WidgetTester'ı kullanarak widget oluşturmak**
Ardından, WidgetTester tarafından sağlanan `pumpWidget()` methodunu kullanarak MyWidget'ı test ortamı içinde oluşturun. `pumpWidget` methodu, sağlanan widget'ı oluşturur ve işler.

`pumpWidget()`'a yapılan ilk çağrıdan sonra, WidgetTester aynı parçacığı yeniden oluşturmak için ek yollar sağlar. Bu, bir StatefulWidget veya animasyonlarla çalışıyorsanız kullanışlıdır.

Örneğin, bir butona dokunmak setState() öğesini çağırır, ancak Flutter test ortamında widget'ınızı otomatik olarak yeniden oluşturmaz. Flutter'dan widget'ı yeniden oluşturmasını istemek için aşağıdaki yöntemlerden birini kullanın.

**tester.pump(Duration duration)**
**tester.pumpAndSettle():** Verilen süre boyunca tekrar tekrar pump()'ı çağırır. Bu, esasen, tüm animasyonların tamamlanmasını bekler.

**expect(actual, matcher);**

Bir widget'ın mevcut olup olmadığını kontrol etmek istiyorsanız expect methodunu kullanabilirsiniz.

Örneğin API'ye kayıt işleminden sonra "İşlem başarılı" mesajı gösteren bir uygulamanız olduğunu düşünün. Bu durumda bu mesajın görünüp görünmediğini kontrol etmek için expect methodunu kullanabilirsiniz.

actual parametresi finder değeri alır, matcher parametresi ise eşleşme düzeyini belirtir.

Örnek senaryomuzdan devam edecek olursak 1 adet "İşlem başarılı" mesajının mevcut olup olmadığını kontrol etmek istersek:

```
final Finder successTxtFinder= find.text('Kayıt Başarılı');

expect(successTxtFinder, findsOneWidget);
```

Buradaki `findsOneWidget` parametresi ile kastedilen şey finder'ın "Kayıt başarılı" mesajından bir tane bulması gerektiğidir. Aynı mesajdan birden fazla bulunması durumunda testimiz hata verir. Bulucunun(finder) bir veya daha fazla widget bulmasını istediğinizde `findsWidgets` parametresini kullanabilirsiniz.


## Matchers
Eşleştirici(Matchers) sınıfları, test paketinin temel bir parçasıdır ve belirli bir değerin beklentileri karşıladığını doğrulamak için ortak bir yol sağlar.

`findsWidgets`: bulucunun (finder) bir veya daha fazla widget bulmasını istediğinizde findsWidgets parametresini,
`findsOneWidget`: bulucunun tam olarak bir widget bulmasını istediğinizde parametresini,
`findsNWidgets`: bulucunun widget ağacında belirtilen sayı kadar widget'ı bulmasını istediğinizde,
`findsAtLeastNWidgets`: bulucunun en azından belirli sayıda widget bulmasını istediğinizde ise findsAtLeastNWidgets parametresini kullanabilirsiniz.
`matchesGoldenFile:` Bir widget'ın oluşturma işleminin belirli bir bitmap görüntüsüyle eşleştiğini doğrular.



Save text'inden hiç bulunmaması durmu
```
 expect(find.text('Save'), findsNothing); 
```

Save text'inin 1 kez bulunması durmu
```
 expect(find.text('Save'), findsOneWidget);
```

Save text'inden widget ağacında tam olarak 2 tane bulunması durumu
```
expect(find.text('Save'), findsNWidgets(2));
```

Save text'inden widget ağacında en az 2 tane bulunması durumu
```
expect(find.text('Save'), findsAtLeastNWidgets(2));
```

## Yaygın kullanılan finder methodları

flutter_test paketi tarafından sağlanan find constant'ı, test ortamında widget'ların yerini belirlemenin birkaç yolunu sağlar.

**byElementType:** Belirli bir türdeki öğeleri arayarak widget'ları bulur.


Örneğin text tipinde bir widget'ı aramak için:

```
expect(find.byElementType(Text), findsOneWidget);
```

**byIcon:** Parametre olarak verilen icon'u arar.


```
expect(find.byIcon(Icons.inbox), findsOneWidget);
```

**byKey:" Parametre olarak aldığı anahtar(key) değerine sahip olan widget'ı arar.


```
expect(find.byKey(const Key("your_key")), findsOneWidget);
```

örnek:

```
testWidgets('finds a widget using a Key', (tester) async {
// Test key tanımlayın.
  const testKey = Key('K');

// testKey ile bir MaterialApp oluşturun.
  await tester.pumpWidget(MaterialApp(key: testKey, home: Container()));

  // testKey'i kullanarak MaterialApp widget'ını bulun.
  expect(find.byKey(testKey), findsOneWidget);
});
```


**bySemanticsLabel:** RegExp.hasMatch veya string eşitliği ile verilen label ile eşleşen Semantik widget'larını bulur.


```
expect(find.bySemanticsLabel('Back'), findsOneWidget);
```

**bySubtype:** Belirli bir türü uygulayan widget'ları arar.

Bu eşleştirici alt türleri kabul eder. Örneğin, bir bySubtype<StatefulWidget>() herhangi bir stateful widget'ı bulacaktır.

```
expect(find.bySubtype<IconButton>(), findsOneWidget);
```

**byTooltip:** Verilen mesajla Tooltip widget'larını bulur.

```
expect(find.byTooltip('Back'), findsOneWidget);
```


**byType:** Parametre olarak aldığı türe sahip olan widgetları arar.

```
expect(find.byType(IconButton), findsOneWidget);
```

**byWidget:** Parametre olarak verilen widget'ı arar.

```
// Böyle bir butonunuz olduğunu varsayalım
Widget myButton = Button(
  child: Text('Update')
);

// Bu şekilde bulabilir ve üzerine tıklayabilirsiniz:
tester.tap(find.byWidget(myButton));
```

bir diğer örnek:

```
testWidgets('finds a specific instance', (tester) async {
  const childWidget = Padding(padding: EdgeInsets.zero);

  await tester.pumpWidget(Container(child: childWidget));

 expect(find.byWidget(childWidget), findsOneWidget);
});
```




**byWidgetPredicate:** Bir widget predicate'i kullanarak widget'ları bulur.

```
expect(find.byWidgetPredicate(
  (Widget widget) => widget is Tooltip && widget.message == 'Back',
  description: 'widget with tooltip "Back"',
), findsOneWidget);
```


**image:**
Verilen image parametresiyle aynı resmi içeren Image ve FadeInImage widget'larını döndürür.

```
expect(find.image(FileImage(File(filePath))), findsOneWidget);
```


**text:**
Parametre olarak aldığı metin değeriyle eşleşen (birebir aynı metin olmaları gerekir) Text, EditableText ve RichText widget'larını arar.


findRichText parametresi false ise, tüm bağımsız RichText widget'ları yok sayılır ve metin Text.data veya Text.textSpan ile eşleştirilir. findRichText parametresi true ise, RichText widget'ları (ve dolayısıyla Text ve Text.rich widget'ları), InlineSpan.toPlainText verilen metinle karşılaştırılarak eşleştirilir.


EditableText widget'ları için metin her zaman EditableText.controller'ın geçerli değeriyle karşılaştırılır.

"Back" string'ini içeren Text, Text.rich ve EditableText widget'larını bulur.

```
expect(find.text('Back'), findsOneWidget);
```

"Close" string'ini içeren Text, Text.rich, EditableText, ve  RichText widget'larını bulur.

```
expect(find.text('Close', findRichText: true), findsOneWidget);
```


**textContaining:** parametre olarak aldığı metin değerini içerin Text, EditableText ve RichText widget'larını arar.

findRichText parametresi false ise, tüm bağımsız RichText widget'ları yok sayılır ve metin Text.data veya Text.textSpan ile eşleştirilir. findRichText parametresi true ise, RichText widget'ları (ve dolayısıyla Text ve Text.rich widget'ları), InlineSpan.toPlainText verilen string ile karşılaştırılarak eşleştirilir.

EditableText widget'ları için desen her zaman EditableText.controller'ın mevcut değeriyle karşılaştırılır.


**widgetWithIcon:**

Parametre olarak aldığı widget ve icon değeriyle eşleşen widget'ları bulur.


```
// İçinde 'arrow_forward' ikonu olan bir butonunuz olduğunu varsayalım:
Button(
  child: Icon(Icons.arrow_forward)
)

// Bu şekilde bulabilir ve üzerine dokunabilirsiniz:
tester.tap(find.widgetWithIcon(Button, Icons.arrow_forward));
```

**widgetWithImage:**
Parametre olarak aldığı widget ve resim değeriyle eşleşen widget'ları bulur.

```
// İçinde resim olan bir butonunuz olduğunu varsayalım:
Button(
  child: Image.file(filePath)
)

// Bu şekilde bulabilir ve üzerine dokunabilirsiniz:
tester.tap(find.widgetWithImage(Button, FileImage(filePath)));
```


**widgetWithText:** Parametre olarak aldığı widget ve onun child'ı olan Text widget'ının metin değeriyle eşleşen widget'ları bulur.

```
// İçinde 'Güncelle' yazan bir butonunuz olduğunu varsayalım:
Button(
  child: Text('Update')
)

// Bu şekilde bulabilir ve üzerine dokunabilirsiniz:
tester.tap(find.widgetWithText(Button, 'Update'));
```

## WidgetTester Methodları

**pumpWidget:** Widget'ı build eder

**enterText:** TextField'a metin girmeyi sağlar.

```
testWidgets('Add and remove a todo', (tester) async {
  await tester.pumpWidget(const TodoList());

  // TextField'e 'hi' yazar.
  await tester.enterText(find.byType(TextField), 'hi');
});
```


**dragFrom:** Verilen ofsete göre kaydırma hareketi uygular.

```
tester.drag(finder, offset)
```

```
testWidgets('Add and remove a todo', (tester) async {

// Kapatmak için öğeyi kaydırın.
  await tester.drag(find.byType(Dismissible), const Offset(500.0, 0.0));

// Kapatma animasyonu bitene kadar widget'ı oluşturun.
  await tester.pumpAndSettle();

// Öğenin artık ekranda olmadığından emin olun.
  expect(find.text('hi'), findsNothing);
});
```

**dragUntilVisible:**  Finder görüntülenene kadar kaydırma hareketini yineler.

moveStep kadar sürükleme işlemi denendikten sonra finder bulunamazsa bir StateError atar.

```
tester.dragUntilVisible(finder, view, moveStep)
```

**tap:** Parametre olarak aldığı finder değeriyle eşleşen widget'a dokunur.

```
await tester.tap(find.byType(FloatingActionButton));
```

**ensureVisible:** Parametre olarak aldığı finder değerini buluna kadar widget'ı kaydırır.


```
      await tester.ensureVisible(find.text("Gülsen")); //Gülsen yazısını buluncaya kadar ekranı kaydırır.
```

**longPress**: Parametre olarak aldığı finder değeriyle eşleşen widget a uzun süre dokunur.

**pageBack**: Scaffold'daki geri düğmesine dokunur.

**press:** Parametre olarak aldığı finder değeriyle eşleşen widget'ın ortasına dokunur.


**printToConsole:** Verilen mesajla debugPrint'i çağırır.

**restartAndRestore:** Uygulama yeniden başlatıldıktan sonra widget ağacının state'ini geri yüklemeyi simüle eder.

**scrollUntilVisible:** Parametre olarak aldığı finder değeriyle eşleşen widget görüntüleninceye kadar   Scrollable.axisDirection  yönünde kaydırma işlemi uygular.


Bu, henüz oluşturulmamış finder'ı aramanıza izin vermesi bakımından ensureVisible'dan farklıdır.

Resources: https://github.com/flutter/flutter/blob/master/packages/flutter_test/lib/src/matchers.dart
https://api.flutter.dev/flutter/flutter_test/flutter_test-library.html
https://api.flutter.dev/flutter/flutter_test/WidgetTester-class.html
https://docs.flutter.dev/cookbook/testing/widget/tap-drag
https://docs.flutter.dev/cookbook/testing/widget/introduction