Flutter ऐप्लिकेशन को टेस्ट करने का तरीका

1. परिचय

Flutter, Google का यूज़र इंटरफ़ेस (यूआई) टूलकिट है. इसकी मदद से, एक ही कोड बेस से मोबाइल, वेब, और डेस्कटॉप पर सुंदर और मूल रूप से कंपाइल किए गए ऐप्लिकेशन बनाए जा सकते हैं.

इस कोडलैब में, एक आसान Flutter ऐप्लिकेशन बनाकर उसे टेस्ट किया जा सकता है. स्थिति मैनेज करने के लिए, ऐप्लिकेशन Provider पैकेज का इस्तेमाल करेगा.

आप इन चीज़ों के बारे में जानेंगे

  • विजेट टेस्टिंग फ़्रेमवर्क का इस्तेमाल करके, विजेट की जांच करने का तरीका
  • integration_test लाइब्रेरी का इस्तेमाल करके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) और परफ़ॉर्मेंस की जांच करने के लिए इंटिग्रेशन टेस्ट बनाने का तरीका
  • यूनिट टेस्ट की मदद से, डेटा क्लास (सेवा देने वाली कंपनियां) को टेस्ट करने का तरीका

आपको क्या बनाना होगा

इस कोडलैब में, आपको आइटम की सूची के साथ एक आसान ऐप्लिकेशन बनाना होगा. हम आपको सोर्स कोड देते हैं, ताकि आप सीधे जांच के लिए जा सकें. ऐप्लिकेशन में ये कार्रवाइयां की जा सकती हैं:

  • आइटम को 'पसंदीदा' में जोड़ा जा रहा है
  • पसंदीदा आइटम की सूची देखी जा रही है
  • पसंदीदा सूची से आइटम हटाए जा रहे हैं

ऐप्लिकेशन पूरा होने के बाद, आपको नीचे दिए गए टेस्ट करने होंगे:

  • जोड़ने और हटाने की कार्रवाइयों की पुष्टि करने के लिए यूनिट टेस्ट
  • होम और पसंदीदा पेजों के लिए विजेट की जांच
  • इंटिग्रेशन टेस्ट का इस्तेमाल करके, पूरे ऐप्लिकेशन के लिए यूज़र इंटरफ़ेस (यूआई) और परफ़ॉर्मेंस की जांच

Android पर चल रहे ऐप्लिकेशन का GIF

आपको इस कोडलैब से क्या सीखना है?

मुझे इस विषय के बारे में पता नहीं है और मुझे इसके बारे में खास जानकारी चाहिए. मुझे इस विषय के बारे में कुछ पता है, लेकिन मुझे इस बारे में फिर से जानना है. मुझे अपने प्रोजेक्ट में इस्तेमाल करने के लिए, उदाहरण के तौर पर एक कोड चाहिए. मुझे किसी खास चीज़ के बारे में जानकारी चाहिए.

2. Flutter डेवलपमेंट एनवायरमेंट को सेट अप करें

इस लैब को पूरा करने के लिए, आपको सॉफ़्टवेयर के दो हिस्सों की ज़रूरत होगी—Flutter SDK टूल और एडिटर.

इनमें से किसी भी डिवाइस का इस्तेमाल करके, कोडलैब चलाया जा सकता है:

  • आपके कंप्यूटर से कनेक्ट किया गया Android या iOS डिवाइस होना चाहिए और वह डेवलपर मोड पर सेट होना चाहिए.
  • iOS सिम्युलेटर (Xcode टूल इंस्टॉल करना ज़रूरी है).
  • Android Emulator (Android Studio में सेटअप करना ज़रूरी है).
  • ब्राउज़र (डीबग करने के लिए Chrome ज़रूरी है).
  • Windows, Linux या macOS डेस्कटॉप ऐप्लिकेशन के तौर पर. आपको उस प्लैटफ़ॉर्म पर गेम बनाना होगा जहां आपको इसे डिप्लॉय करना है. इसलिए, अगर आपको Windows डेस्कटॉप ऐप्लिकेशन डेवलप करना है, तो आपको सही बिल्ड चेन ऐक्सेस करने के लिए Windows पर डेवलप करना होगा. ऑपरेटिंग सिस्टम से जुड़ी कुछ खास शर्तें हैं, जिनके बारे में docs.flutter.dev/desktop पर जानकारी दी गई है.

3. शुरू करना

नया Flutter ऐप्लिकेशन बनाएं और डिपेंडेंसी अपडेट करें

इस कोडलैब का फ़ोकस, Flutter मोबाइल ऐप्लिकेशन को टेस्ट करने पर होता है. कॉपी करके चिपकाई जाने वाली सोर्स फ़ाइलों का इस्तेमाल करके, टेस्ट करने के लिए, ऐप्लिकेशन तुरंत तैयार किया जाएगा. इसके बाद, कोडलैब का बाकी हिस्सा अलग-अलग तरह की टेस्टिंग को सीखने पर फ़ोकस करता है.

a3c16fc17be25f6c.pngFlutter ऐप्लिकेशन का इस्तेमाल शुरू करना में दिए गए निर्देशों का इस्तेमाल करके या कमांड लाइन पर, यहां बताए गए तरीके से, टेंप्लेट वाला एक सामान्य Flutter ऐप्लिकेशन बनाएं.

$ flutter create --empty testing_app
Creating project testing_app...
Resolving dependencies in `testing_app`... 
Downloading packages... 
Got dependencies in `testing_app`.
Wrote 128 files.

All done!
You can find general documentation for Flutter at: https://docs.flutter.dev/
Detailed API documentation is available at: https://api.flutter.dev/
If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev

In order to run your empty application, type:

  $ cd testing_app
  $ flutter run

Your empty application code is in testing_app/lib/main.dart.

a3c16fc17be25f6c.pngकमांड लाइन पर pub डिपेंडेंसी जोड़ें.

  • राज्य के आसान मैनेजमेंट के लिए, provider,
  • integration_test, डिवाइसों और एम्युलेटर पर Flutter कोड को खुद टेस्ट करने के लिए दिया गया है,
  • flutter_driver, ताकि रीयल डिवाइसों और एम्युलेटर पर चलने वाले Flutter ऐप्लिकेशन की जांच करने के लिए बेहतर एपीआई मिल सके,
  • सामान्य टेस्ट टूल के लिए test,
  • ऐप्लिकेशन नेविगेशन मैनेज करने के लिए, go_router.
$ cd testing_app
$ flutter pub add provider go_router dev:test 'dev:flutter_driver:{"sdk":"flutter"}' 'dev:integration_test:{"sdk":"flutter"}'
Resolving dependencies... 
Downloading packages... 
+ _fe_analyzer_shared 67.0.0 (68.0.0 available)
+ analyzer 6.4.1 (6.5.0 available)
+ args 2.5.0
+ convert 3.1.1
+ coverage 1.7.2
+ crypto 3.0.3
+ file 7.0.0
+ flutter_driver 0.0.0 from sdk flutter
+ flutter_web_plugins 0.0.0 from sdk flutter
+ frontend_server_client 4.0.0
+ fuchsia_remote_debug_protocol 0.0.0 from sdk flutter
+ glob 2.1.2
+ go_router 14.0.2
+ http_multi_server 3.2.1
+ http_parser 4.0.2
+ integration_test 0.0.0 from sdk flutter
+ io 1.0.4
+ js 0.7.1
  leak_tracker 10.0.4 (10.0.5 available)
  leak_tracker_flutter_testing 3.0.3 (3.0.5 available)
+ logging 1.2.0
  material_color_utilities 0.8.0 (0.11.1 available)
  meta 1.12.0 (1.14.0 available)
+ mime 1.0.5
+ nested 1.0.0
+ node_preamble 2.0.2
+ package_config 2.1.0
+ platform 3.1.4
+ pool 1.5.1
+ process 5.0.2
+ provider 6.1.2
+ pub_semver 2.1.4
+ shelf 1.4.1
+ shelf_packages_handler 3.0.2
+ shelf_static 1.1.2
+ shelf_web_socket 1.0.4
+ source_map_stack_trace 2.1.1
+ source_maps 0.10.12
+ sync_http 0.3.1
+ test 1.25.2 (1.25.4 available)
  test_api 0.7.0 (0.7.1 available)
+ test_core 0.6.0 (0.6.2 available)
+ typed_data 1.3.2
+ watcher 1.1.0
+ web 0.5.1
+ web_socket_channel 2.4.5
+ webdriver 3.0.3
+ webkit_inspection_protocol 1.2.1
+ yaml 3.1.2
Changed 44 dependencies!
9 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

आपके pubspec.yaml में ये डिपेंडेंसी होनी चाहिए:

pubspec.yaml

name: testing_app
description: "A new Flutter project."
publish_to: 'none'
version: 0.1.0

environment:
  sdk: '>=3.4.0-0 <4.0.0'

dependencies:
  flutter:
    sdk: flutter
  go_router: ^14.0.2
  provider: ^6.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0
  test: ^1.25.2
  flutter_driver:
    sdk: flutter
  integration_test:
    sdk: flutter

flutter:
  uses-material-design: true

a3c16fc17be25f6c.pngप्रोजेक्ट को अपनी पसंद के कोड एडिटर में खोलें और ऐप्लिकेशन को चलाएं. वैकल्पिक रूप से, इसे कमांड लाइन पर इस तरह चलाएं.

$ flutter run

4. ऐप्लिकेशन बनाएं

इसके बाद, आप ऐप्लिकेशन बनाएंगे, ताकि आप उसकी जांच कर सकें. ऐप्लिकेशन में ये फ़ाइलें शामिल होती हैं:

  • lib/models/favorites.dart - पसंदीदा सूची के लिए मॉडल क्लास बनाता है
  • lib/screens/favorites.dart - पसंदीदा सूची के लिए लेआउट बनाता है
  • lib/screens/home.dart - आइटम की सूची बनाता है
  • lib/main.dart - मुख्य फ़ाइल जहां से ऐप्लिकेशन शुरू होता है

सबसे पहले, lib/models/favorites.dart में Favorites मॉडल बनाएं

a3c16fc17be25f6c.pnglib डायरेक्ट्री में models नाम की एक नई डायरेक्ट्री बनाएं और फिर favorites.dart नाम की एक नई फ़ाइल बनाएं. उस फ़ाइल में यह कोड जोड़ें:

lib/models/favorites.dart

import 'package:flutter/material.dart';

/// The [Favorites] class holds a list of favorite items saved by the user.
class Favorites extends ChangeNotifier {
  final List<int> _favoriteItems = [];

  List<int> get items => _favoriteItems;

  void add(int itemNo) {
    _favoriteItems.add(itemNo);
    notifyListeners();
  }

  void remove(int itemNo) {
    _favoriteItems.remove(itemNo);
    notifyListeners();
  }
}

lib/screens/favorites.dart में पसंदीदा पेज जोड़ें

a3c16fc17be25f6c.pnglib डायरेक्ट्री में, screens नाम की एक नई डायरेक्ट्री बनाएं और उस डायरेक्ट्री में favorites.dart नाम की एक नई फ़ाइल बनाएं. उस फ़ाइल में यह कोड जोड़ें:

lib/screens/favorites.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../models/favorites.dart';

class FavoritesPage extends StatelessWidget {
  const FavoritesPage({super.key});

  static String routeName = 'favorites_page';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Favorites'),
      ),
      body: Consumer<Favorites>(
        builder: (context, value, child) => ListView.builder(
          itemCount: value.items.length,
          padding: const EdgeInsets.symmetric(vertical: 16),
          itemBuilder: (context, index) => FavoriteItemTile(value.items[index]),
        ),
      ),
    );
  }
}

class FavoriteItemTile extends StatelessWidget {
  const FavoriteItemTile(this.itemNo, {super.key});

  final int itemNo;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
        ),
        title: Text(
          'Item $itemNo',
          key: Key('favorites_text_$itemNo'),
        ),
        trailing: IconButton(
          key: Key('remove_icon_$itemNo'),
          icon: const Icon(Icons.close),
          onPressed: () {
            Provider.of<Favorites>(context, listen: false).remove(itemNo);
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(
                content: Text('Removed from favorites.'),
                duration: Duration(seconds: 1),
              ),
            );
          },
        ),
      ),
    );
  }
}

lib/screens/home.dart में होम पेज जोड़ें

a3c16fc17be25f6c.pnglib/screens डायरेक्ट्री में, home.dart नाम की दूसरी नई फ़ाइल बनाएं. lib/screens/home.dart में यह कोड जोड़ें:

lib/screens/home.dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import '../models/favorites.dart';
import 'favorites.dart';

class HomePage extends StatelessWidget {
  static String routeName = '/';

  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Testing Sample'),
        actions: <Widget>[
          TextButton.icon(
            onPressed: () {
              context.go('/${FavoritesPage.routeName}');
            },
            icon: const Icon(Icons.favorite_border),
            label: const Text('Favorites'),
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: 100,
        cacheExtent: 20.0,
        padding: const EdgeInsets.symmetric(vertical: 16),
        itemBuilder: (context, index) => ItemTile(index),
      ),
    );
  }
}

class ItemTile extends StatelessWidget {
  final int itemNo;

  const ItemTile(this.itemNo, {super.key});

  @override
  Widget build(BuildContext context) {
    var favoritesList = Provider.of<Favorites>(context);

    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
        ),
        title: Text(
          'Item $itemNo',
          key: Key('text_$itemNo'),
        ),
        trailing: IconButton(
          key: Key('icon_$itemNo'),
          icon: favoritesList.items.contains(itemNo)
              ? const Icon(Icons.favorite)
              : const Icon(Icons.favorite_border),
          onPressed: () {
            !favoritesList.items.contains(itemNo)
                ? favoritesList.add(itemNo)
                : favoritesList.remove(itemNo);
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(favoritesList.items.contains(itemNo)
                    ? 'Added to favorites.'
                    : 'Removed from favorites.'),
                duration: const Duration(seconds: 1),
              ),
            );
          },
        ),
      ),
    );
  }
}

lib/main.dart की सामग्री बदलें

a3c16fc17be25f6c.pnglib/main.dart की सामग्री को इस कोड से बदलें:

lib/main.dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'models/favorites.dart';
import 'screens/favorites.dart';
import 'screens/home.dart';

void main() {
  runApp(const TestingApp());
}

final _router = GoRouter(
  routes: [
    GoRoute(
      path: HomePage.routeName,
      builder: (context, state) {
        return const HomePage();
      },
      routes: [
        GoRoute(
          path: FavoritesPage.routeName,
          builder: (context, state) {
            return const FavoritesPage();
          },
        ),
      ],
    ),
  ],
);

class TestingApp extends StatelessWidget {
  const TestingApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Favorites>(
      create: (context) => Favorites(),
      child: MaterialApp.router(
        title: 'Testing Sample',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(
            seedColor: Colors.deepPurple,
          ),
          useMaterial3: true,
        ),
        routerConfig: _router,
      ),
    );
  }
}

ऐप्लिकेशन अब पूरा हो गया है, लेकिन इसकी जांच नहीं की गई है.

a3c16fc17be25f6c.pngऐप्लिकेशन चलाएं. यह इस स्क्रीनशॉट की तरह दिखना चाहिए:

b74f843e42a28b0f.png

यह ऐप्लिकेशन, आइटम की सूची दिखाता है. दिल का आकार भरने और आइटम को पसंदीदा आइटम की सूची में जोड़ने के लिए, किसी भी पंक्ति में मौजूद दिल के आकार वाले आइकॉन पर टैप करें. AppBar पर मौजूद पसंदीदा बटन, आपको दूसरी स्क्रीन पर ले जाता है, जिसमें पसंदीदा की सूची होती है.

ऐप्लिकेशन अब टेस्टिंग के लिए तैयार है. अगले चरण में, ऐप्लिकेशन की टेस्टिंग शुरू की जाएगी.

5. यूनिट की जांच करने वाली कंपनी

आपको सबसे पहले, favorites मॉडल की यूनिट टेस्टिंग करनी होगी. यूनिट टेस्ट क्या है? यूनिट टेस्ट से इस बात की पुष्टि होती है कि सॉफ़्टवेयर की हर इकाई, चाहे वह फ़ंक्शन हो, ऑब्जेक्ट हो या विजेट, अपने तय किए गए टास्क को सही तरीके से करता हो.

इंटिग्रेशन की जांच को छोड़कर, Flutter ऐप्लिकेशन में मौजूद सभी टेस्ट फ़ाइलें test डायरेक्ट्री में रखी जाती हैं.

test/widget_test.dart को हटाएं

a3c16fc17be25f6c.pngजांच शुरू करने से पहले, widget_test.dart फ़ाइल मिटा दें. आपको अपनी टेस्ट फ़ाइलें जोड़नी होंगी.

नई टेस्ट फ़ाइल बनाएं

सबसे पहले, आपको Favorites मॉडल में add() तरीके की जांच करके, यह पुष्टि करनी होगी कि सूची में कोई नया आइटम जोड़ा गया है और यह कि सूची में हुए बदलाव को दिखाती है या नहीं. नियम के मुताबिक, test डायरेक्ट्री में मौजूद डायरेक्ट्री स्ट्रक्चर, lib डायरेक्ट्री और Dart फ़ाइलों के नाम जैसा ही है, जिनमें _test जुड़ा है.

a3c16fc17be25f6c.pngtest डायरेक्ट्री में एक models डायरेक्ट्री बनाएं. इस नई डायरेक्ट्री में, इस कॉन्टेंट के साथ एक favorites_test.dart फ़ाइल बनाएं:

test/models/favorites_test.dart

import 'package:test/test.dart';
import 'package:testing_app/models/favorites.dart';

void main() {
  group('Testing App Provider', () {
    var favorites = Favorites();

    test('A new item should be added', () {
      var number = 35;
      favorites.add(number);
      expect(favorites.items.contains(number), true);
    });    
  });
}

Flutter टेस्टिंग फ़्रेमवर्क की मदद से, ग्रुप में एक-दूसरे से जुड़े मिलते-जुलते टेस्ट बाइंड किए जा सकते हैं. एक टेस्ट फ़ाइल में कई ग्रुप हो सकते हैं, जिनका मकसद lib डायरेक्ट्री में मौजूद मिलती-जुलती फ़ाइल के अलग-अलग हिस्सों की जांच करना है.

test() तरीके में दो पोज़िशनल पैरामीटर इस्तेमाल किए जाते हैं: टेस्ट का description और callback जहां टेस्ट लिखा जाता है.

a3c16fc17be25f6c.pngसूची से किसी आइटम को हटाकर, यह जांच करें. उसी Testing App Provider ग्रुप में यह टेस्ट डालें:

test/models/favorites_test.dart

test('An item should be removed', () {
  var number = 45;
  favorites.add(number);
  expect(favorites.items.contains(number), true);
  favorites.remove(number);
  expect(favorites.items.contains(number), false);
});

जांच करना

a3c16fc17be25f6c.pngकमांड लाइन पर, प्रोजेक्ट की रूट डायरेक्ट्री पर जाएं और यह कमांड डालें:

$ flutter test test/models/favorites_test.dart 

अगर सब कुछ काम करता है, तो आपको इस तरह का मैसेज दिखेगा:

00:06 +2: All tests passed!                                                    

टेस्ट फ़ाइल का पूरा वर्शन: test/models/favorites_test.dart.

यूनिट टेस्टिंग के बारे में ज़्यादा जानकारी के लिए, यूनिट टेस्टिंग के बारे में जानकारी पर जाएं.

6. विजेट की जांच

इस चरण में, आपको विजेट की जांच करने के लिए कोड जोड़ना होगा. विजेट की जांच, Flutter के लिए खास नहीं है. इसमें हर विजेट की अलग-अलग जांच की जा सकती है. यह चरण HomePage और FavoritesPage स्क्रीन की अलग-अलग जांच करता है.

विजेट की जांच करने के लिए, test() फ़ंक्शन के बजाय, testWidget() फ़ंक्शन का इस्तेमाल किया जाता है. test() फ़ंक्शन की तरह ही, testWidget() फ़ंक्शन भी दो पैरामीटर का इस्तेमाल करता है: description, और callback. हालांकि, कॉलबैक WidgetTester को तर्क के तौर पर लेता है.

विजेट की जांच में TestFlutterWidgetsBinding का इस्तेमाल किया जाता है. यह एक ऐसी क्लास है जो आपके विजेट को वही संसाधन उपलब्ध कराती है जो वे किसी चल रहे ऐप्लिकेशन पर ले सकते थे, जैसे कि स्क्रीन के साइज़ और ऐनिमेशन शेड्यूल करने की सुविधा के बारे में जानकारी, लेकिन ऐप्लिकेशन के अंदर चलाए बिना. इसके बजाय, विजेट को इंस्टैंशिएट करने और नतीजों की जांच करने के लिए, वर्चुअल एनवायरमेंट का इस्तेमाल किया जाता है. यहां pumpWidget, फ़्रेमवर्क को यह बताकर प्रोसेस शुरू करता है कि किसी खास विजेट को ठीक वैसे ही माउंट और मेज़र करें जैसा कि वह किसी ऐप्लिकेशन में करता.

विजेट की जांच करने वाला फ़्रेमवर्क, text(), byType(), और byIcon(). जैसे विजेट ढूंढने के लिए आइडेंटिफ़ायर उपलब्ध कराता है. यह फ़्रेमवर्क, नतीजों की पुष्टि करने के लिए मैचर भी उपलब्ध कराता है.

HomePage विजेट को टेस्ट करके शुरुआत करें.

नई टेस्ट फ़ाइल बनाएं

पहले टेस्ट में यह पुष्टि की जाती है कि HomePage को स्क्रोल करने की सुविधा ठीक से काम कर रही है या नहीं.

a3c16fc17be25f6c.pngtest डायरेक्ट्री में एक नई फ़ाइल बनाएं और उसे home_test.dart नाम दें. नई फ़ाइल में, यह कोड जोड़ें:

test/home_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/home.dart';

Widget createHomeScreen() => ChangeNotifierProvider<Favorites>(
      create: (context) => Favorites(),
      child: const MaterialApp(
        home: HomePage(),
      ),
    );

void main() {
  group('Home Page Widget Tests', () {
    testWidgets('Testing Scrolling', (tester) async {
      await tester.pumpWidget(createHomeScreen());
      expect(find.text('Item 0'), findsOneWidget);
      await tester.fling(
        find.byType(ListView),
        const Offset(0, -200),
        3000,
      );
      await tester.pumpAndSettle();
      expect(find.text('Item 0'), findsNothing);
    });
  });
}

createHomeScreen() फ़ंक्शन का इस्तेमाल ऐसा ऐप्लिकेशन बनाने के लिए किया जाता है जो MaterialApp में टेस्ट किए जाने वाले विजेट को लोड करता है. इसे चेंजनोटिफ़ायर में रैप किया जाता है. HomePage विजेट के ऊपर विजेट ट्री में ये दोनों विजेट मौजूद होने चाहिए, ताकि वह उनसे इनहेरिट कर सके और उनके डेटा का ऐक्सेस पा सके. इस फ़ंक्शन को pumpWidget() फ़ंक्शन में पैरामीटर के तौर पर पास किया जाता है.

इसके बाद, देखें कि फ़्रेमवर्क, स्क्रीन पर रेंडर किए गए ListView को ढूंढ सकता है या नहीं.

a3c16fc17be25f6c.pnghome_test.dart में यह कोड स्निपेट जोड़ें:

test/home_test.dart

group('Home Page Widget Tests', () {

  // BEGINNING OF NEW CONTENT
  testWidgets('Testing if ListView shows up', (tester) async {  
    await tester.pumpWidget(createHomeScreen());
    expect(find.byType(ListView), findsOneWidget);
  });                                                
  // END OF NEW CONTENT

    testWidgets('Testing Scrolling', (tester) async {
      await tester.pumpWidget(createHomeScreen());
      expect(find.text('Item 0'), findsOneWidget);
      await tester.fling(
        find.byType(ListView),
        const Offset(0, -200),
        3000,
      );
      await tester.pumpAndSettle();
      expect(find.text('Item 0'), findsNothing);
    });
});

जांच करना

सबसे पहले, इस कमांड के साथ जांच को उसी तरह चलाएं जैसे आप यूनिट टेस्ट करते हैं:

$ flutter test test/home_test.dart 

जांच तुरंत हो जानी चाहिए और आपको ऐसा मैसेज दिखेगा:

00:02 +2: All tests passed!                                                    

किसी डिवाइस या एम्युलेटर का इस्तेमाल करके भी, विजेट के टेस्ट किए जा सकते हैं. इससे, टेस्ट को रन करते समय देखा जा सकता है. इसमें आपको हॉट रीस्टार्ट की सुविधा भी मिलती है.

a3c16fc17be25f6c.pngअपने डिवाइस को प्लग-इन करें या एम्युलेटर चालू करें. आप इस जांच को डेस्कटॉप ऐप्लिकेशन के तौर पर भी चला सकते हैं.

a3c16fc17be25f6c.pngकमांड लाइन से, प्रोजेक्ट की रूट डायरेक्ट्री पर जाएं और यह निर्देश डालें:

$ flutter run test/home_test.dart 

जांच करने के लिए, आपको डिवाइस चुनना पड़ सकता है. इस स्थिति में, निर्देशों का पालन करें और कोई डिवाइस चुनें:

Multiple devices found:
Linux (desktop) • linux  • linux-x64      • Ubuntu 22.04.1 LTS 5.15.0-58-generic
Chrome (web)    • chrome • web-javascript • Google Chrome 109.0.5414.119
[1]: Linux (linux)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"): 

अगर सब कुछ काम करता है, तो आपको नीचे दिया गया कुछ जैसा आउटपुट दिखेगा:

Launching test/home_test.dart on Linux in debug mode...
Building Linux application...                                           
flutter: 00:00 +0: Home Page Widget Tests Testing if ListView shows up
Syncing files to device Linux...                                    62ms

Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).

💪 Running with sound null safety 💪

An Observatory debugger and profiler on Linux is available at: http://127.0.0.1:35583/GCpdLBqf2UI=/
flutter: 00:00 +1: Home Page Widget Tests Testing Scrolling
The Flutter DevTools debugger and profiler on Linux is available at:
http://127.0.0.1:9100?uri=http://127.0.0.1:35583/GCpdLBqf2UI=/
flutter: 00:02 +2: All tests passed!

इसके बाद, आपको टेस्ट फ़ाइल में बदलाव करना होगा और ऐप्लिकेशन को फिर से चालू करने के लिए Shift + R दबाएं. इसके बाद, सभी टेस्ट फिर से चलाएं. ऐप्लिकेशन को बंद न करें.

a3c16fc17be25f6c.pngHomePage विजेट को टेस्ट करने वाले ग्रुप में और टेस्ट जोड़ें. नीचे दिए गए टेस्ट को अपनी फ़ाइल में कॉपी करें:

test/home_test.dart

testWidgets('Testing IconButtons', (tester) async {
  await tester.pumpWidget(createHomeScreen());
  expect(find.byIcon(Icons.favorite), findsNothing);
  await tester.tap(find.byIcon(Icons.favorite_border).first);
  await tester.pumpAndSettle(const Duration(seconds: 1));
  expect(find.text('Added to favorites.'), findsOneWidget);
  expect(find.byIcon(Icons.favorite), findsWidgets);
  await tester.tap(find.byIcon(Icons.favorite).first);
  await tester.pumpAndSettle(const Duration(seconds: 1));
  expect(find.text('Removed from favorites.'), findsOneWidget);
  expect(find.byIcon(Icons.favorite), findsNothing);
});

इस टेस्ट से इस बात की पुष्टि की जाती है कि IconButton पर टैप करने से यह आइकॉन, Icons.favorite_border (ओपन हार्ट) से Icons.favorite (भरा हुआ दिल) में बदल जाता है. इसके बाद, दोबारा टैप करने पर Icons.favorite_border पर वापस आ जाता है.

a3c16fc17be25f6c.pngShift + R डालें. ऐसा करने पर, ऐप्लिकेशन रीस्टार्ट हो जाता है और सभी जांच फिर से हो जाती हैं.

टेस्ट फ़ाइल में दी गई पूरी जानकारी: test/home_test.dart.

a3c16fc17be25f6c.pngनीचे दिए गए कोड से FavoritesPage की जांच करने के लिए, इसी प्रक्रिया का इस्तेमाल करें. इन्हीं चरणों का पालन करें और उसे चलाएं.

test/favorites_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';

late Favorites favoritesList;

Widget createFavoritesScreen() => ChangeNotifierProvider<Favorites>(
      create: (context) {
        favoritesList = Favorites();
        return favoritesList;
      },
      child: const MaterialApp(
        home: FavoritesPage(),
      ),
    );

void addItems() {
  for (var i = 0; i < 10; i += 2) {
    favoritesList.add(i);
  }
}

void main() {
  group('Favorites Page Widget Tests', () {
    testWidgets('Test if ListView shows up', (tester) async {
      await tester.pumpWidget(createFavoritesScreen());
      addItems();
      await tester.pumpAndSettle();
      expect(find.byType(ListView), findsOneWidget);
    });

    testWidgets('Testing Remove Button', (tester) async {
      await tester.pumpWidget(createFavoritesScreen());
      addItems();
      await tester.pumpAndSettle();
      var totalItems = tester.widgetList(find.byIcon(Icons.close)).length;
      await tester.tap(find.byIcon(Icons.close).first);
      await tester.pumpAndSettle();
      expect(tester.widgetList(find.byIcon(Icons.close)).length,
          lessThan(totalItems));
      expect(find.text('Removed from favorites.'), findsOneWidget);
    });
  });
}

इस टेस्ट से इस बात की पुष्टि की जाती है कि 'बंद करें (हटाएं)' बटन दबाने पर, कोई आइटम गायब है या नहीं.

विजेट की जांच करने के बारे में ज़्यादा जानकारी के लिए, यहां जाएं:

7. इंटिग्रेशन की जांच के साथ ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) की जांच करना

इंटिग्रेशन टेस्ट का इस्तेमाल यह जांचने के लिए किया जाता है कि किसी ऐप्लिकेशन के अलग-अलग हिस्से एक साथ कैसे काम करते हैं. integration_test लाइब्रेरी का इस्तेमाल, Flutter में इंटिग्रेशन टेस्ट करने के लिए किया जाता है. यह Flutter का Selenium WebDriver, Proactor, Espresso या अर्ल ग्रे वर्शन है. पैकेज, डिवाइस पर टेस्ट चलाने के लिए अंदरूनी तौर पर flutter_driver का इस्तेमाल करता है.

Flutter में इंटिग्रेशन टेस्ट लिखना, विजेट टेस्ट को लिखने जैसा ही है. हालांकि, इसमें यह बात नहीं है कि इंटिग्रेशन की जांच, टारगेट डिवाइस कहे जाने वाले मोबाइल डिवाइस, ब्राउज़र या डेस्कटॉप ऐप्लिकेशन पर की जाती हैं.

टेस्ट लिखें

a3c16fc17be25f6c.pngप्रोजेक्ट की रूट डायरेक्ट्री में integration_test नाम की एक डायरेक्ट्री बनाएं और उस डायरेक्ट्री में app_test.dart नाम की एक नई फ़ाइल बनाएं.

integration_test/app_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:testing_app/main.dart';

void main() {
  group('Testing App', () {
    testWidgets('Favorites operations test', (tester) async {
      await tester.pumpWidget(const TestingApp());

      final iconKeys = [
        'icon_0',
        'icon_1',
        'icon_2',
      ];

      for (var icon in iconKeys) {
        await tester.tap(find.byKey(ValueKey(icon)));
        await tester.pumpAndSettle(const Duration(seconds: 1));

        expect(find.text('Added to favorites.'), findsOneWidget);
      }

      await tester.tap(find.text('Favorites'));
      await tester.pumpAndSettle();

      final removeIconKeys = [
        'remove_icon_0',
        'remove_icon_1',
        'remove_icon_2',
      ];

      for (final iconKey in removeIconKeys) {
        await tester.tap(find.byKey(ValueKey(iconKey)));
        await tester.pumpAndSettle(const Duration(seconds: 1));

        expect(find.text('Removed from favorites.'), findsOneWidget);
      }
    });
  });
}

जांच करना

a3c16fc17be25f6c.pngअपने डिवाइस को प्लग-इन करें या एम्युलेटर चालू करें. आप इस जांच को डेस्कटॉप ऐप्लिकेशन के तौर पर भी चला सकते हैं.

a3c16fc17be25f6c.pngकमांड लाइन पर, प्रोजेक्ट की रूट डायरेक्ट्री पर जाएं और यह कमांड डालें:

$ flutter test integration_test/app_test.dart

अगर सब कुछ काम करता है, तो आपको इस तरह का आउटपुट दिखेगा:

Multiple devices found:
Linux (desktop) • linux  • linux-x64      • Ubuntu 22.04.1 LTS 5.15.0-58-generic
Chrome (web)    • chrome • web-javascript • Google Chrome 109.0.5414.119
[1]: Linux (linux)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"): 1
00:00 +0: loading /home/miquel/tmp/testing_app/integration_test/app_test.dart                                                B00:08 +0: loading /home/miquel/tmp/testing_app/integration_test/app_test.dart                                                
00:26 +1: All tests passed!

8. Flutter ड्राइवर की मदद से ऐप्लिकेशन की परफ़ॉर्मेंस की जांच करना

परफ़ॉर्मेंस टेस्ट लिखना

नीचे दिए गए कॉन्टेंट के साथ integration_test फ़ोल्डर में perf_test.dart नाम की एक नई टेस्ट फ़ाइल बनाएं:

integration_test/perf_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:testing_app/main.dart';

void main() {
  group('Testing App Performance', () {
    final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
    binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;

    testWidgets('Scrolling test', (tester) async {
      await tester.pumpWidget(const TestingApp());

      final listFinder = find.byType(ListView);

      await binding.traceAction(() async {
        await tester.fling(listFinder, const Offset(0, -500), 10000);
        await tester.pumpAndSettle();

        await tester.fling(listFinder, const Offset(0, 500), 10000);
        await tester.pumpAndSettle();
      }, reportKey: 'scrolling_summary');
    });
  });
}

ensureInitialized() फ़ंक्शन यह पुष्टि करता है कि इंटिग्रेशन टेस्ट ड्राइवर शुरू किया गया है या नहीं. साथ ही, ज़रूरत पड़ने पर इसे फिर से शुरू किया जाता है. framePolicy को fullyLive पर सेट करके, ऐनिमेशन वाले कोड की जांच की जा सकती है.

यह टेस्ट, आइटम की सूची में तेज़ी से स्क्रोल करता है और फिर ऊपर की ओर स्क्रोल करता है. traceAction() फ़ंक्शन, कार्रवाइयों को रिकॉर्ड करता है और टाइमलाइन से जुड़ी खास जानकारी जनरेट करता है.

परफ़ॉर्मेंस के नतीजे कैप्चर करें

नतीजे कैप्चर करने के लिए, perf_driver.dart नाम की फ़ाइल के साथ test_driver नाम का फ़ोल्डर बनाएं और यह कोड जोड़ें:

test_driver/perf_driver.dart

import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';

Future<void> main() {
  return integrationDriver(
    responseDataCallback: (data) async {
      if (data != null) {
        final timeline = driver.Timeline.fromJson(
            data['scrolling_summary'] as Map<String, dynamic>);

        final summary = driver.TimelineSummary.summarize(timeline);

        await summary.writeTimelineToFile(
          'scrolling_summary',
          pretty: true,
          includeSummary: true,
        );
      }
    },
  );
}

जांच करना

a3c16fc17be25f6c.pngअपने डिवाइस को प्लग-इन करें या एम्युलेटर चालू करें.

a3c16fc17be25f6c.pngकमांड लाइन पर, प्रोजेक्ट की रूट डायरेक्ट्री पर जाएं और यह कमांड डालें:

$ flutter drive \
  --driver=test_driver/perf_driver.dart \
  --target=integration_test/perf_test.dart \
  --profile \
  --no-dds

अगर सब कुछ काम करता है, तो आपको इस तरह का आउटपुट दिखेगा:

Running "flutter pub get" in testing_app...
Resolving dependencies... 
  archive 3.3.2 (3.3.6 available)
  collection 1.17.0 (1.17.1 available)
  js 0.6.5 (0.6.7 available)
  matcher 0.12.13 (0.12.14 available)
  meta 1.8.0 (1.9.0 available)
  path 1.8.2 (1.8.3 available)
  test 1.22.0 (1.23.0 available)
  test_api 0.4.16 (0.4.18 available)
  test_core 0.4.20 (0.4.23 available)
  vm_service 9.4.0 (11.0.1 available)
  webdriver 3.0.1 (3.0.2 available)
Got dependencies!
Running Gradle task 'assembleProfile'...                         1,379ms
✓  Built build/app/outputs/flutter-apk/app-profile.apk (14.9MB).
Installing build/app/outputs/flutter-apk/app-profile.apk...        222ms
I/flutter ( 6125): 00:04 +1: Testing App Performance (tearDownAll)
I/flutter ( 6125): 00:04 +2: All tests passed!
All tests passed.

जांच पूरी होने के बाद, प्रोजेक्ट के रूट में मौजूद बिल्ड डायरेक्ट्री में दो फ़ाइलें होंगी:

  1. scrolling_summary.timeline_summary.json में खास जानकारी होती है. फ़ाइल में मौजूद जानकारी की समीक्षा करने के लिए, उसे किसी भी टेक्स्ट एडिटर में खोलें.
  2. scrolling_summary.timeline.json में टाइमलाइन का पूरा डेटा मौजूद है.

इंटिग्रेशन की जांच करने के बारे में ज़्यादा जानकारी के लिए, यहां जाएं:

9. बधाई हो!

आपने कोडलैब पूरा कर लिया है और Flutter ऐप्लिकेशन को टेस्ट करने के अलग-अलग तरीके सीख लिए हैं.

आपने क्या सीखा

  • यूनिट टेस्ट की मदद से, सेवा देने वाली कंपनियों की जांच करने का तरीका
  • विजेट टेस्टिंग फ़्रेमवर्क का इस्तेमाल करके विजेट की जांच करने का तरीका
  • इंटिग्रेशन टेस्ट का इस्तेमाल करके, ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) की जांच करने का तरीका
  • इंटिग्रेशन टेस्ट का इस्तेमाल करके, ऐप्लिकेशन की परफ़ॉर्मेंस की जांच करने का तरीका

Flutter में टेस्टिंग के बारे में ज़्यादा जानने के लिए यहां जाएं