কিভাবে একটি Flutter অ্যাপ পরীক্ষা করবেন

1. ভূমিকা

Flutter হল Google-এর UI টুলকিট যা একটি একক কোডবেস থেকে মোবাইল, ওয়েব এবং ডেস্কটপের জন্য সুন্দর, স্থানীয়ভাবে সংকলিত অ্যাপ্লিকেশন তৈরির জন্য।

এই কোডল্যাবে, আপনি একটি সাধারণ ফ্লাটার অ্যাপ তৈরি এবং পরীক্ষা করবেন। অ্যাপটি রাজ্য পরিচালনার জন্য প্রদানকারী প্যাকেজ ব্যবহার করবে।

আপনি কি শিখবেন

  • উইজেট টেস্টিং ফ্রেমওয়ার্ক ব্যবহার করে কীভাবে উইজেট পরীক্ষা তৈরি করবেন
  • integration_test লাইব্রেরি ব্যবহার করে অ্যাপের UI এবং কর্মক্ষমতা পরীক্ষা করার জন্য কীভাবে একটি ইন্টিগ্রেশন টেস্ট তৈরি করবেন
  • ইউনিট পরীক্ষার সাহায্যে ডেটা ক্লাস (প্রোভাইডার) কীভাবে পরীক্ষা করবেন

আপনি কি নির্মাণ করবেন

এই কোডল্যাবে, আপনি আইটেমগুলির একটি তালিকা সহ একটি সাধারণ অ্যাপ্লিকেশন তৈরি করে শুরু করবেন। আমরা আপনার জন্য সোর্স কোড প্রদান করি যাতে আপনি সঠিক পরীক্ষায় যেতে পারেন। অ্যাপটি নিম্নলিখিত ক্রিয়াকলাপগুলিকে সমর্থন করে:

  • পছন্দের আইটেম যোগ করা
  • পছন্দের তালিকা দেখছেন
  • পছন্দের তালিকা থেকে আইটেমগুলি সরানো হচ্ছে

অ্যাপটি সম্পূর্ণ হয়ে গেলে, আপনি নিম্নলিখিত পরীক্ষাগুলি লিখবেন:

  • ক্রিয়াকলাপগুলি যোগ এবং অপসারণ বৈধ করতে ইউনিট পরীক্ষা
  • হোম এবং প্রিয় পৃষ্ঠাগুলির জন্য উইজেট পরীক্ষা
  • ইন্টিগ্রেশন পরীক্ষা ব্যবহার করে সমগ্র অ্যাপের জন্য UI এবং কর্মক্ষমতা পরীক্ষা

অ্যান্ড্রয়েডে চলমান অ্যাপটির জিআইএফ

আপনি এই কোডল্যাব থেকে কি শিখতে চান?

আমি এই বিষয়ে নতুন, এবং আমি একটি ভাল ওভারভিউ চাই। আমি এই বিষয় সম্পর্কে কিছু জানি, কিন্তু আমি একটি রিফ্রেশার চাই. আমি আমার প্রকল্পে ব্যবহার করার জন্য একটি উদাহরণ কোড খুঁজছি। আমি নির্দিষ্ট কিছু একটি ব্যাখ্যা খুঁজছি.

2. আপনার ফ্লটার ডেভেলপমেন্ট এনভায়রনমেন্ট সেট আপ করুন

এই ল্যাবটি সম্পূর্ণ করার জন্য আপনার দুটি টুকরো সফ্টওয়্যার প্রয়োজন - ফ্লাটার SDK এবং একটি সম্পাদক

আপনি এই ডিভাইসগুলির যেকোনো একটি ব্যবহার করে কোডল্যাব চালাতে পারেন:

  • আপনার কম্পিউটারের সাথে সংযুক্ত এবং বিকাশকারী মোডে সেট করা একটি শারীরিক Android বা iOS ডিভাইস৷
  • আইওএস সিমুলেটর (এক্সকোড সরঞ্জাম ইনস্টল করা প্রয়োজন)।
  • অ্যান্ড্রয়েড এমুলেটর (অ্যান্ড্রয়েড স্টুডিওতে সেটআপ প্রয়োজন)।
  • একটি ব্রাউজার (ডিবাগিংয়ের জন্য Chrome প্রয়োজন)।
  • একটি Windows , Linux , বা macOS ডেস্কটপ অ্যাপ্লিকেশন হিসাবে। আপনি যে প্ল্যাটফর্মে স্থাপন করার পরিকল্পনা করছেন সেখানে আপনাকে অবশ্যই বিকাশ করতে হবে। সুতরাং, আপনি যদি একটি উইন্ডোজ ডেস্কটপ অ্যাপ বিকাশ করতে চান, তাহলে যথাযথ বিল্ড চেইন অ্যাক্সেস করতে আপনাকে অবশ্যই উইন্ডোজে বিকাশ করতে হবে। অপারেটিং সিস্টেম-নির্দিষ্ট প্রয়োজনীয়তা রয়েছে যা docs.flutter.dev/desktop- এ বিস্তারিতভাবে কভার করা হয়েছে।

3. শুরু করা

একটি নতুন Flutter অ্যাপ তৈরি করুন এবং নির্ভরতা আপডেট করুন

এই কোডল্যাব একটি Flutter মোবাইল অ্যাপ পরীক্ষা করার উপর দৃষ্টি নিবদ্ধ করে। আপনি কপি এবং পেস্ট করা উত্স ফাইলগুলি ব্যবহার করে পরীক্ষা করার জন্য আপনি দ্রুত অ্যাপটি তৈরি করবেন। কোডল্যাবের বাকি অংশ তখন বিভিন্ন ধরণের পরীক্ষা শেখার উপর দৃষ্টি নিবদ্ধ করে।

a3c16fc17be25f6c.png একটি সাধারণ টেমপ্লেটেড ফ্লাটার অ্যাপ তৈরি করুন, হয় আপনার প্রথম ফ্লাটার অ্যাপের সাথে শুরু করা নির্দেশাবলী ব্যবহার করে বা নিম্নরূপ কমান্ড লাইনে।

$ 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 কমান্ড লাইনে পাব নির্ভরতা যোগ করুন।

  • সহজ রাষ্ট্র পরিচালনার জন্য provider ,
  • ডিভাইস এবং এমুলেটরগুলিতে ফ্লটার কোডের স্ব-ড্রাইভিং পরীক্ষার জন্য integration_test ,
  • flutter_driver একটি উন্নত API-এর জন্য ফ্লাটার অ্যাপ্লিকেশন পরীক্ষা করার জন্য যা বাস্তব ডিভাইস এবং এমুলেটরগুলিতে চলে,
  • সাধারণ পরীক্ষার টুলিংয়ের জন্য 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.dartFavorites মডেল তৈরি করুন

a3c16fc17be25f6c.png lib ডিরেক্টরিতে 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.png lib ডিরেক্টরিতে 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.png lib/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.png নিম্নলিখিত কোড দিয়ে lib/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 ডিরেক্টরিতে এবং ডার্ট ফাইলগুলির _test সংযোজিত একই নাম রয়েছে।

a3c16fc17be25f6c.png test ডিরেক্টরিতে একটি 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);
    });    
  });
}

ফ্লাটার টেস্টিং ফ্রেমওয়ার্ক আপনাকে একটি গ্রুপে একে অপরের সাথে সম্পর্কিত অনুরূপ পরীক্ষাগুলি আবদ্ধ করতে দেয়। 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. উইজেট পরীক্ষা

এই ধাপে আপনি পরীক্ষা উইজেটগুলিতে কোড যোগ করবেন। উইজেট পরীক্ষা ফ্লটারের জন্য অনন্য, যেখানে আপনি প্রতিটি উইজেটকে একটি বিচ্ছিন্ন ফ্যাশনে পরীক্ষা করতে পারেন। এই ধাপটি HomePage এবং FavoritesPage স্ক্রীন পৃথকভাবে পরীক্ষা করে।

উইজেট টেস্টিং test( test() ফাংশনের পরিবর্তে testWidget() ফাংশন ব্যবহার করে। test() ফাংশনের মতো, testWidget() ফাংশন দুটি প্যারামিটার নেয়: description, এবং callback , তবে কলব্যাকটি তার যুক্তি হিসাবে একটি WidgetTester নেয়।

উইজেট পরীক্ষাগুলি TestFlutterWidgetsBinding ব্যবহার করে, একটি ক্লাস যা আপনার উইজেটগুলিতে একই সংস্থান সরবরাহ করে যা তাদের একটি চলমান অ্যাপে থাকবে, যেমন স্ক্রীনের আকার সম্পর্কে তথ্য, অ্যানিমেশনের সময়সূচী করার ক্ষমতা, কিন্তু একটি অ্যাপের ভিতরে না চললে। পরিবর্তে, একটি ভার্চুয়াল এনভায়রনমেন্ট ব্যবহার করা হয় উইজেটকে ইনস্ট্যান্টিয়েট করার জন্য, এবং তারপরে ফলাফল পরীক্ষা করে। এখানে, pumpWidget ফ্রেমওয়ার্ককে একটি নির্দিষ্ট উইজেট মাউন্ট এবং পরিমাপ করার কথা বলে প্রক্রিয়াটি শুরু করে ঠিক যেমনটি এটি একটি অ্যাপ্লিকেশনে।

উইজেট টেস্টিং ফ্রেমওয়ার্ক ফাইন্ডারদের উইজেটগুলি খুঁজে পেতে প্রদান করে, উদাহরণস্বরূপ text() , byType() , এবং byIcon(). ফ্রেমওয়ার্ক ফলাফল যাচাই করার জন্য ম্যাচার্স প্রদান করে।

HomePage উইজেট পরীক্ষা করে শুরু করুন।

একটি নতুন পরীক্ষা ফাইল তৈরি করুন

প্রথম পরীক্ষা HomePage স্ক্রোল করা সঠিকভাবে কাজ করে কিনা তা যাচাই করে।

a3c16fc17be25f6c.png test ডিরেক্টরিতে একটি নতুন ফাইল তৈরি করুন এবং এটির নাম দিন 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-এ পরীক্ষা করার জন্য উইজেট লোড করে, একটি ChangeNotifierProvider-এ মোড়ানো। হোমপেজ উইজেটের এই দুটি উইজেটকে উইজেট ট্রিতে এর উপরে উপস্থিত থাকতে হবে যাতে এটি তাদের কাছ থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হতে পারে এবং তাদের অফার করা ডেটাতে অ্যাক্সেস পেতে পারে। এই ফাংশনটি pumpWidget() ফাংশনে একটি প্যারামিটার হিসাবে পাস করা হয়।

এরপরে, ফ্রেমওয়ার্কটি স্ক্রিনে রেন্ডার করা একটি ListView খুঁজে পেতে পারে কিনা তা পরীক্ষা করুন।

a3c16fc17be25f6c.png home_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.png হোমপেজ উইজেট পরীক্ষা করে এমন গ্রুপে আরও পরীক্ষা যোগ করুন। আপনার ফাইলে নিম্নলিখিত পরীক্ষাটি অনুলিপি করুন:

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.png Shift + 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. ইন্টিগ্রেশন টেস্ট সহ অ্যাপ UI পরীক্ষা করা

ইন্টিগ্রেশন পরীক্ষাগুলি একটি অ্যাপের পৃথক টুকরোগুলি সামগ্রিকভাবে একসাথে কীভাবে কাজ করে তা পরীক্ষা করতে ব্যবহৃত হয়। integration_test লাইব্রেরিটি ফ্লটারে ইন্টিগ্রেশন পরীক্ষা করতে ব্যবহৃত হয়। এটি সেলেনিয়াম ওয়েবড্রাইভার, প্রটেক্টর, এসপ্রেসো বা আর্ল গ্রে-এর ফ্লটারের সংস্করণ। প্যাকেজটি একটি ডিভাইসে পরীক্ষা চালানোর জন্য অভ্যন্তরীণভাবে flutter_driver ব্যবহার করে।

ফ্লাটারে ইন্টিগ্রেশন পরীক্ষা লেখা উইজেট টেস্ট লেখার অনুরূপ, এই ব্যতিক্রম ব্যতীত যে ইন্টিগ্রেশন পরীক্ষাগুলি লক্ষ্য ডিভাইস নামে একটি মোবাইল ডিভাইস, ব্রাউজার বা ডেস্কটপ অ্যাপ্লিকেশনে চলে।

পরীক্ষা লিখুন

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. ফ্লটার ড্রাইভারের সাথে অ্যাপের কার্যক্ষমতা পরীক্ষা করা

একটি কর্মক্ষমতা পরীক্ষা লিখুন

নিম্নলিখিত বিষয়বস্তু সহ 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 অ্যাপ পরীক্ষা করার বিভিন্ন উপায় শিখেছেন।

আপনি কি শিখেছেন

  • ইউনিট পরীক্ষার সাহায্যে প্রদানকারীদের কিভাবে পরীক্ষা করবেন
  • উইজেট টেস্টিং ফ্রেমওয়ার্ক ব্যবহার করে কীভাবে উইজেট পরীক্ষা করবেন
  • ইন্টিগ্রেশন টেস্ট ব্যবহার করে অ্যাপের UI কীভাবে পরীক্ষা করবেন
  • ইন্টিগ্রেশন টেস্ট ব্যবহার করে অ্যাপের পারফরম্যান্স কীভাবে পরীক্ষা করবেন

ফ্লটারে পরীক্ষা সম্পর্কে আরও জানতে, দেখুন