Flutter Unit Testing with Mockito multiple stubs - flutter

I'm quite new to unit testing and I want to test a method of a service that calls conditionally a second method. The problem I'm facing now is that I'm getting a missing MissingStubError even I have created the missing stub.
mockito: 5.3.2
Error Message:
MissingStubError: 'createCashbookItem'
No stub was found which matches the arguments of this method call:
createCashbookItem(Instance of 'CashbookItem')
Test:
#GenerateMocks([CashbookRepository, ReceiptRepository, CashbookItemRepository])
void main() {
late BookingService bookingService;
late MockCashbookRepository mockCashbookRepository;
late MockCashbookItemRepository mockCashbookItemRepository;
late MockReceiptRepository mockReceiptRepository;
setUp(() {
mockCashbookRepository = MockCashbookRepository();
mockCashbookItemRepository = MockCashbookItemRepository();
mockReceiptRepository = MockReceiptRepository();
bookingService = BookingServiceImpl(
receiptRepository: mockReceiptRepository,
cashbookItemRepository: mockCashbookItemRepository,
cashbookRepository: mockCashbookRepository,
);
});
group("bookings", () {
var t_OldReceipt = Receipt.empty();
var t_NewReceipt = Receipt.empty();
test("create booking", () async {
t_OldReceipt = t_OldReceipt.copyWith(
amount: 10,
totalAmount: 10,
taking: true,
category: "test",
taxRate: 0,
paymentType: kPaymentTypeBar,
documentNumber: "1",
taxAmount: 0,
receiptDate: DateTime.now(),
year: "2023",
yearMonth: "20232",
yearMonthDay: "2023210",
contact: Contact.empty());
// arrange
var cashbookItem = CashbookItem.fromReceipt(t_OldReceipt);
when(mockReceiptRepository.createReceipt(t_OldReceipt)).thenAnswer((realInvocation) async => const Right(unit));
when(mockCashbookItemRepository.createCashbookItem(cashbookItem)).thenAnswer((realInvocation) async => const Right(unit));
// act
final result = await bookingService.createBooking(t_OldReceipt);
// assert
expect(result, const Right(unit));
});
});
}
Method that I want to test:
Future<Either<ReceiptFailure, Unit>> createBooking(Receipt receipt) async {
Either<ReceiptFailure, Unit>? receiptFailureOrSuccess;
Either<cashbook_failures.CashbookFailure, Unit>? cashbookFailureOrSuccess;
receiptFailureOrSuccess = await receiptRepository.createReceipt(receipt);
if (receiptFailureOrSuccess.isLeft()) {
return receiptFailureOrSuccess;
}
if (receipt.paymentType == kPaymentTypeBar) {
cashbookFailureOrSuccess = await cashbookItemRepository.createCashbookItem(CashbookItem.fromReceipt(receipt));
if(cashbookFailureOrSuccess.isLeft()){
receiptRepository.deleteReceipt(receipt.id.value);
return left(CreateCashbookItemFromReceiptFailure());
} else {
return right(unit);
}
}
return receiptFailureOrSuccess;
}
I have added a stub for the error and my assumption was that it is possible to have two stubs in one test. I want to test if the method createCashbookItem inside createBooking is called.

Related

How to use any state management for my bluetooth app?

I am trying to use a connected bluetooth device on other pages, but I'm unable to do that. I tried to use the provider, but that did not work, parameter passing did not work either.
After testing, I am using the following
I made a class ReactiveProvider
class ReactiveProvider(){
Stream<ConnectionStateUpdate> get currentConnectionStream {
return flutterReactiveBle.connectToAdvertisingDevice(
id: _foundBleUARTDevices[index].id,
prescanDuration: const Duration(seconds: 1),
withServices: [_uartUuid, _uartRx, _uartTx],
);
}
}
and setup in start
void main() {
runApp(
MultiProvider(providers: [
StreamProvider<ConnectionStateUpdate>(
create: (context) => ReactiveProvider().currentConnectionStream,
initialData: const ConnectionStateUpdate(
deviceId: "",
connectionState: DeviceConnectionState.disconnected,
failure: null),
)
], child: const MainApp()),
);
}
and in StatefullWidget
final _currentConnectionStream = Provider.of<ConnectionStateUpdate>(context);
I got the errors
The instance member 'context' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
and
The method 'listen' isn't defined for the type 'ConnectionStateUpdate'.
Try correcting the name to the name of an existing method, or defining a method named 'listen'.
In following function
_connection = _currentConnectionStream.listen((event) {});
I want to access the following parameters on another page using any state management
final flutterReactiveBle = FlutterReactiveBle();
List<DiscoveredDevice> _foundBleUARTDevices = [];
late StreamSubscription<DiscoveredDevice> _scanStream;
late Stream<ConnectionStateUpdate> _currentConnectionStream;
late StreamSubscription<ConnectionStateUpdate> _connection;
late QualifiedCharacteristic _txCharacteristic;
//late QualifiedCharacteristic _rxCharacteristic;
late Stream<List<int>> _receivedDataStream;
These are other functions I am using
void onNewReceivedData(List<int> data) {
_numberOfMessagesReceived += 1;
_receivedData
.add("$_numberOfMessagesReceived: ${String.fromCharCodes(data)}");
if (_receivedData.length > 10) {
_receivedData.removeAt(0);
}
}
void _disconnect() async {
await _connection.cancel();
_connected = false;
}
void _stopScan() async {
await _scanStream.cancel();
_scanning = false;
}
void _startScan() async {
_foundBleUARTDevices = [];
_scanning = true;
_scanStream = flutterReactiveBle
.scanForDevices(withServices: [_uartUuid]).listen((device) {
if (_foundBleUARTDevices.every((element) => element.id != device.id)) {
_foundBleUARTDevices.add(device);
}
}, onError: (Object error) {
_logTexts = "${_logTexts}ERROR while scanning:$error \n";
}, onDone: () async {
await _scanStream.cancel();
_scanning = false;
});
}
void onConnectDevice(index) {
_currentConnectionStream = flutterReactiveBle.connectToAdvertisingDevice(
id: _foundBleUARTDevices[index].id,
prescanDuration: const Duration(seconds: 1),
withServices: [_uartUuid, _uartRx, _uartTx],
);
_logTexts = "";
_connection = _currentConnectionStream.listen((event) {
var id = event.deviceId.toString();
switch (event.connectionState) {
case DeviceConnectionState.connecting:
{
_logTexts = "${_logTexts}Connecting to $id\n";
break;
}
case DeviceConnectionState.connected:
{
_connected = true;
_logTexts = "${_logTexts}Connected to $id\n";
_numberOfMessagesReceived = 0;
_receivedData = [];
_txCharacteristic = QualifiedCharacteristic(
serviceId: _uartUuid,
characteristicId: _uartTx,
deviceId: event.deviceId);
_receivedDataStream =
flutterReactiveBle.subscribeToCharacteristic(_txCharacteristic);
_receivedDataStream.listen((data) {
onNewReceivedData(data);
}, onError: (dynamic error) {
_logTexts = "${_logTexts}Error:$error$id\n";
});
break;
}
case DeviceConnectionState.disconnecting:
{
_connected = false;
_logTexts = "${_logTexts}Disconnecting from $id\n";
break;
}
case DeviceConnectionState.disconnected:
{
_logTexts = "${_logTexts}Disconnected from $id\n";
break;
}
}
});
}
Another question I have, is how I can use or keep connected using on void onConnectDevice(index) function, because as per the provider you don't need to pass the parameters.

How to setup blocTest for a feature that requires authentication?

So I'm implementing blocTesting for my flutter project and I'm using real apis in testing as that is what I've been asked to do. Apparently when I'm trying out blocTesting for a feature that requires authentication the api is giving back a null response but in the running app it is working fine...
I'm adding the respective files below for the same. Also the name of feature is client and I'm trying to fetch all clients here.
Client_bloc_test.dart
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:injectable/injectable.dart' as inject;
import 'package:mynovatium/app/helper/injections/shared_preference/shared_preference_injection_configuration.dart';
import 'package:mynovatium/features/buy/models/test_model.dart';
import 'package:mynovatium/features/client/bloc/client_bloc.dart';
import 'package:mynovatium/features/client/models/private_client_model.dart';
import 'package:mynovatium/features/login/bloc/authentication/authentication_bloc.dart';
import 'package:mynovatium/features/login/repositories/authentication_repository.dart';
void main() async {
await configureInjection(inject.Environment.test);
final AuthenticationBloc authenticationBloc = AuthenticationBloc();
group('ClientBloc', () {
late PrivateClientModel client;
test('initial state of the bloc is [SignupInitial]', () {
expect(
ClientBloc(authenticationBloc: authenticationBloc).state,
ClientInitial(),
);
});
group('ClientCreateClient', () {
blocTest<ClientBloc, ClientState>(
'emits [ClientLoadInProgress, ClientLoadSuccess] '
'state when successfully fetched clients',
setUp: () async {
client = PrivateClientModel(1, List<TestModel>.empty(), createdAt: DateTime.now(), gender: 'Male', firstName: 'Nikunj', lastName: 'goyal', birthDate: '03/07/2001', ssnr: '0000', email: 'nik#gmail.com', telephoneNumber: '6641234123', street: 'Abcd', zipCode: '6020', city: 'Tyrol');
},
build: () => ClientBloc(authenticationBloc: authenticationBloc),
act: (ClientBloc bloc) => bloc..add(const ClientGetClients(101010)),
expect: () => <dynamic>[
const ClientLoadInProgress(),
],
);
});
});
}
Client_bloc.dart
Future<void> _onGetClients(ClientGetClients event, Emitter<ClientState> emit) async {
// Skip double loadings
if (state is ClientLoadInProgress) return;
PrivateClientModelList _pcml = PrivateClientModelList(<PrivateClientModel>[]);
final PrivateRedeemModel _prm = PrivateRedeemModel(customerId: event.userId, clients: <RedeemClient>[]);
if (state is ClientLoadSuccess) {
final ClientLoadSuccess _currentState = state as ClientLoadSuccess;
_pcml = _currentState.pcml;
try {
emit(const ClientLoadInProgress());
_pcml = await _clientRepository.getClientsForUser(event.userId);
} catch (e) {
final KBMException _exception = e as KBMException;
emit(ClientLoadFailure(exception: _exception));
}
return emit(_currentState.copyWith(pcml: _pcml));
} else {
try {
emit(const ClientLoadInProgress());
_pcml = await _clientRepository.getClientsForUser(event.userId);
for (final PrivateClientModel _client in _pcml.data) {
_prm.clients.add(RedeemClient(clientId: _client.id, quantity: 0));
}
} catch (e) {
final KBMException _exception = e as KBMException;
emit(ClientLoadFailure(exception: _exception));
}
return emit(ClientLoadSuccess(_pcml, _prm));
}
}
In the above code when 'getClientsForUser' is being called the response is null.

Mokito wont return a stubbed value

I started TDD recently and it has slowed my progress, I m trying to stub a return value with Mockito, but i keep getting "null is not a subtype of Future-dynamic' not sure what i did wrong, here is my setup
class ImageSelectorMock extends Mock implements ImageSelector {}
getImageSelectorMock({logo}) {
_unregisterIfRegistered<ImageSelector>();
var imageSelector = ImageSelectorMock();
if (logo != null) {
when(imageSelector.businessLogo).thenReturn('string');
when(imageSelector.uploadImage(null, 'folder'))
.thenAnswer((realInvocation) async =>
Future.value('send this')
);
}
locator.registerSingleton<ImageSelector>(imageSelector);
return imageSelector;
}
setupService() {
//getAuthServiceMock();
//getFirestoreServiceMock();
//getNavigationServiceMock();
getImageSelectorMock();
}
void _unregisterIfRegistered<T extends Object>() {
if (locator.isRegistered<T>()) {
locator.unregister<T>();
}
}
getImageSelectorMock takes an optional arg "logo" to check if imageSelector.uploadImage is called. Also, I'm using a locator/get_it package
group('RegistrationviewmodelTest -', () {
setUp(() => {setupService()});
test('when business logo is NOT null => uplaodImage should be called', () async {
// final navigation = getNavigationServiceMock();
// final fireStore = getFirestoreServiceMock();
final imageSelector = await getImageSelectorMock(logo: "test");
final model = RegistraionViewModel();
await model.createBusiness({
'title': "text",
'description': "text",
});
verify(imageSelector.uploadImage('', 'upload'));
// verify(navigation.navigateTo());
});
});
// uploadImage does
Future uploadImage(file, folder) async {
// String fileName = basename(_imageFile.path);
String fileName = basename(file.path);
final firebaseStorageRef =
FirebaseStorage.instance.ref().child('$folder/$fileName');
final uploadTask = firebaseStorageRef.putFile(file);
final taskSnapshot = await uploadTask;
return taskSnapshot.ref.getDownloadURL().then((value) => value);
}
uploadImage is just an image picker that returns download Url from fire storege.
Thanks for helping out!!

Flutter UI freezes on hash check

I have a program that will check a password with bcrypt library, this is quite computing intensive, so as a result the UI will be stuck for like 2 seconds. It is very annoying and I cannot figure out what to do to stop it.
I want a loader to be shown when the password is being checked.
This is my code:
class _MyWidgetState<MyWidget> extends State{
build() {
return GetPassCode(PassCodeType.ENTER,
onDone: ({context, data}) async {
unlock(state, data?['password'] ?? '', Languages.of(context));
}, goBack: () {}, data: {});
}
unlock(userState, String? password, Languages strings) async {
final user = userState.currentUser;
if (!(await user.checkPassword(password))) {
return;
}
}
context.read<LockCubit>().unlock();
}
}
you can put the caculating into a isolate.
https://api.flutter-io.cn/flutter/dart-isolate/dart-isolate-library.html
here's some example code:
class IsoMessage {
final SendPort? sendPort;
final List<String> args;
IsoMessage(this.sendPort, this.args);
}
String myCaculate(IsoMessage message) {
String result = message.args[0][0] + message.args[1][1];
message.sendPort?.send(result);
return result;
}
here's how to calling the func
var port = ReceivePort();
port.listen((message) {
print("onData: $message");
}, onDone: () {
print('iso close');
}, onError: (error) {
print('iso error: $error');
});
IsoMessage message = IsoMessage(port.sendPort,["asd", "dsa"]);
Isolate.spawn<IsoMessage>(myCaculate, message);

Flutter test with mockito and dartz fails

I'm testing a repository implementation but the test fails and I can't find where the error is.
This is the repository:
class ProductRepositoryImpl implements ProductRepository {
final ProductRemoteDataSource remoteDataSource;
final NetworkInfo networkInfo;
ProductRepositoryImpl(
{#required this.remoteDataSource, #required this.networkInfo});
#override
Future<Either<Failure, List<Product>>> getProducts() async {
this.networkInfo.istConnected;
return Right(await this.remoteDataSource.getProducts());
}
}
This is the test implementation:
class MockRemoteDataSource extends Mock implements ProductRemoteDataSource {}
class MockNetworkInfo extends Mock implements NetworkInfo {}
void main() {
ProductRepositoryImpl repository;
MockRemoteDataSource mockRemoteDataSource;
MockNetworkInfo mockNetworkInfo;
final tProductModel = ProductModel(
id: 1,
title: 'Product 1',
description: 'Product description',
oldPrice: '20.99',
discount: 10,
storeName: 'Zé Strore',
remainingOffers: 3,
imagesUrls: ['https://unsplash.com/photos/EF7BVa9BB2M']);
final productModelList = [tProductModel];
final Product tProduct = tProductModel;
final productList = [tProduct];
setUp(() {
mockRemoteDataSource = MockRemoteDataSource();
mockNetworkInfo = MockNetworkInfo();
repository = ProductRepositoryImpl(
remoteDataSource: mockRemoteDataSource, networkInfo: mockNetworkInfo);
});
group('device is online', () {
setUp(() {
when(mockNetworkInfo.istConnected).thenAnswer((_) async => true);
});
test(
'should return remote data when the call to remote data source is successful',
() async {
// arrange
when(mockRemoteDataSource.getProducts())
.thenAnswer((_) async => productModelList);
// act
final result = await repository.getProducts();
// assert
verify(mockRemoteDataSource.getProducts());
expect(result, equals(Right(productList)));
});
});
}
The error reported is:
Expected: Right<dynamic, List<Product>>:<Right([ProductModel(1, Product 1, Product description, 20.99, 10, Zé Strore, 3, [https://unsplash.com/photos/EF7BVa9BB2M])])>
Actual: Right<Failure, List<Product>>:<Right([ProductModel(1, Product 1, Product description, 20.99, 10, Zé Strore, 3, [https://unsplash.com/photos/EF7BVa9BB2M])])>
package:test_api expect
expect
package:flutter_test/src/widget_tester.dart:441
main.<fn>.<fn>
test/…/repositories/product_repository_impl_test.dart:74
I don't know where is the error. The objects looks like the same. I tried to use expect(result, equals(Right<Failure, List<Product>>(productList)));, but the error persists. The dataSource object has one method and was mocked.
I always did this using the fold method:
final Either<Failure, List<Product>> result = await repository.getProducts();
result.fold((left) => fail('test failed'), (right) {
verify(mockRemoteDataSource.getProducts()).called(1);
expect(right, equals(productList));
});
Don't know if that's the correct way to do it, but for me it worked. Couldn't check it. If it didn't work please let me know!