Skip to main content

mogen_unit_tests 1.4.2 copy "mogen_unit_tests: ^1.4.2" to clipboard
mogen_unit_tests: ^1.4.2 copied to clipboard

Scans Riverpod notifiers and flutter_bloc blocs/cubits, then auto-generates Mocktail and bloc_test unit tests.

example/example.dart

// ignore_for_file: avoid_print

/// This file demonstrates how mogen_unit_tests works end-to-end.
///
/// Given the following feature structure in your Flutter project:
///
/// ```
/// lib/
/// └── features/
///     └── cart/
///         └── presentation/
///             ├── notifiers/
///             │   └── cart_notifier.dart
///             └── states/
///                 └── cart_state.dart
/// ```
///
/// Running `dart run mogen_unit_tests` from your project root generates:
///
/// ```
/// test/
/// └── unit/
///     └── features/
///         └── cart/
///             └── cart_notifier_test.dart
/// ```
///
/// ---
///
/// ## Example input — cart_notifier.dart
///
/// ```dart
/// class CartNotifier extends AsyncNotifier<CartState> {
///   @override
///   Future<CartState> build() async {
///     return ref.read(cartRepositoryProvider).fetchCart();
///   }
///
///   Future<void> addItem(CartItem item) async {
///     await ref.read(cartRepositoryProvider).addItem(item);
///     state = AsyncData(state.requireValue.copyWith(success: 'added'));
///   }
///
///   Future<void> removeItem(String itemId) async {
///     await ref.read(cartRepositoryProvider).removeItem(itemId);
///     state = AsyncData(state.requireValue.copyWith(success: 'removed'));
///   }
/// }
/// ```
///
/// `CartRepository.fetchCart()` returns a `Future<CartEntity>`, `addItem`
/// takes a custom `CartItem` (so mocktail needs a fallback value registered
/// for `any()` to work), and `CartState` exposes
/// `isLoadingAction`/`error`/`success` fields — the generator recognizes all
/// of these conventions and reflects them below. `fetchCart()` is called by
/// `build()`, so it is stubbed once in `setUp` and the error tests re-stub
/// it with `thenThrow` after initialising the notifier.
///
/// ## Example output — cart_notifier_test.dart
///
/// ```dart
/// // GENERATED BY mogen_unit_tests — YOU CAN REMOVE THIS COMMENT
///
/// import 'package:flutter_riverpod/flutter_riverpod.dart';
/// import 'package:flutter_test/flutter_test.dart';
/// import 'package:mocktail/mocktail.dart';
/// import 'package:my_app/core/errors/app_exception.dart';
///
/// import 'package:my_app/features/cart/presentation/notifiers/cart_notifier.dart';
/// import 'package:my_app/features/cart/presentation/states/cart_state.dart';
/// import 'package:my_app/features/cart/domain/repositories/cart_repository.dart';
/// import 'package:my_app/features/cart/data/repositories/cart_repository_impl.dart';
/// import 'package:my_app/features/cart/domain/entities/cart_entity.dart';
/// import 'package:my_app/features/cart/domain/entities/cart_item.dart';
///
/// // ── Mocks ────────────────────────────────────────────────────
/// class MockCartRepository extends Mock implements CartRepository {}
///
/// void main() {
///   TestWidgetsFlutterBinding.ensureInitialized();
///
///   group('CartNotifier', () {
///     late MockCartRepository mockCartRepository;
///     late ProviderContainer container;
///
///     setUpAll(() {
///       // Mocktail needs a fallback instance registered for every
///       // non-nullable custom type used with an any()/captureAny() matcher.
///       registerFallbackValue(CartItem.empty());
///     });
///
///     setUp(() {
///       mockCartRepository = MockCartRepository();
///
///       container = ProviderContainer(
///         overrides: [
///           // Override the provider so the notifier gets mockCartRepository
///           cartRepositoryProvider.overrideWithValue(mockCartRepository),
///         ],
///       );
///
///       // Arrange: stub dependencies used by build() and calls shared
///       // by multiple methods — once here instead of in every test.
///       when(
///         () => mockCartRepository.fetchCart(),
///       ).thenAnswer((_) async => CartEntity.empty());
///     });
///
///     tearDown(() {
///       container.dispose();
///     });
///
///     // ── addItem() ──────────────────────────────────────
///     group('addItem', () {
///       test('addItem completes successfully', () async {
///         // Arrange: stub repositories
///         when(
///           () => mockCartRepository.addItem(any()),
///         ).thenAnswer((_) async => null);
///
///         // Arrange: inputs
///         final item = CartItem.empty();
///
///         // Ensure notifier is initialised
///         await container.read(cartNotifierProvider.future);
///
///         // Act
///         await container.read(cartNotifierProvider.notifier).addItem(item);
///
///         // Assert
///         final finalState = container.read(cartNotifierProvider);
///         expect(finalState.requireValue.isLoadingAction, isFalse);
///         expect(finalState.requireValue.error, isNull);
///         expect(finalState.requireValue.success, isNotNull);
///       });
///
///       test('addItem shows an error when the repository fails', () async {
///         // Arrange: inputs
///         final item = CartItem.empty();
///
///         // Ensure notifier is initialised
///         await container.read(cartNotifierProvider.future);
///
///         // Arrange: make every dependency call this method performs fail.
///         // Re-stubbing overrides the success stubs from setUp().
///         when(
///           () => mockCartRepository.addItem(any()),
///         ).thenThrow(AppException.test());
///
///         // Act
///         await container.read(cartNotifierProvider.notifier).addItem(item);
///
///         // Assert
///         final finalState = container.read(cartNotifierProvider);
///         expect(finalState.requireValue.isLoadingAction, isFalse);
///         expect(finalState.requireValue.error, isNotNull);
///         expect(finalState.requireValue.success, isNull);
///       });
///     });
///
///     // ── removeItem() ──────────────────────────────────────
///     group('removeItem', () {
///       test('removeItem completes successfully', () async {
///         // Arrange: stub repositories
///         when(
///           () => mockCartRepository.removeItem(any()),
///         ).thenAnswer((_) async => null);
///
///         // Arrange: inputs
///         const itemId = '';
///
///         // Ensure notifier is initialised
///         await container.read(cartNotifierProvider.future);
///
///         // Act
///         await container.read(cartNotifierProvider.notifier).removeItem(itemId);
///
///         // Assert
///         final finalState = container.read(cartNotifierProvider);
///         expect(finalState.requireValue.isLoadingAction, isFalse);
///         expect(finalState.requireValue.error, isNull);
///         expect(finalState.requireValue.success, isNotNull);
///       });
///
///       test('removeItem shows an error when the repository fails', () async {
///         // Arrange: inputs
///         const itemId = '';
///
///         // Ensure notifier is initialised
///         await container.read(cartNotifierProvider.future);
///
///         // Arrange: make every dependency call this method performs fail.
///         // Re-stubbing overrides the success stubs from setUp().
///         when(
///           () => mockCartRepository.removeItem(any()),
///         ).thenThrow(AppException.test());
///
///         // Act
///         await container.read(cartNotifierProvider.notifier).removeItem(itemId);
///
///         // Assert
///         final finalState = container.read(cartNotifierProvider);
///         expect(finalState.requireValue.isLoadingAction, isFalse);
///         expect(finalState.requireValue.error, isNotNull);
///         expect(finalState.requireValue.success, isNull);
///       });
///     });
///   });
/// }
/// ```
///
/// This assumes the consuming project defines `AppException.test()` at
/// `lib/core/errors/app_exception.dart`, and that `CartEntity`/`CartItem`
/// expose a `.empty()` factory constructor — see the README's "Conventions
/// this generator assumes" section.

library;

void main() {
  print('Run `dart run mogen_unit_tests` from your Flutter project root.');
}
1
likes
160
points
143
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Scans Riverpod notifiers and flutter_bloc blocs/cubits, then auto-generates Mocktail and bloc_test unit tests.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

analyzer, args, dart_style, glob, path, yaml

More

Packages that depend on mogen_unit_tests