Open DiegoVega19 opened 2 years ago
Hey @DiegoVega19, please format your code first and insert the whole error if you can. 🙏 https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
i know it's been a year but i have the same problem here and for the sake of brevity i'll show only the write function.. and the weird thing is that when i test the saveLocalData isolating the storage.write as you'll see below the test passes but inside my authenticateCrewMember it does not.. my AuthProvider uses the StorageService as a dependency and DI is made with get_it on app load
abstract class StorageService {
Future<bool> write({
required String key,
required String value,
bool deleteAll = false,
});
}
class StorageServiceImpl implements StorageService {
StorageServiceImpl(this._storage);
final FlutterSecureStorage? _storage;
@override
Future<bool> write({
required String key,
required String value,
bool deleteAll = false,
}) async {
try {
await _storage?.write(
key: key,
value: value,
aOptions: getStorageAndroidOptions(),
);
return true;
} on PlatformException catch (e, s) {
log('[PLATFORM-EXCEPTION] - STORAGE-SERVICE:WRITE: $e, $s');
if (deleteAll) {
await _storage?.deleteAll();
}
return false;
} catch (e, s) {
log('[ERROR] - STORAGE-SERVICE:WRITE: $e, $s');
return false;
}
}
}
Auth Provider
class AuthProvider with ChangeNotifier {
AuthProvider({
required this.storageService,
required this.onboardService,
});
final StorageService storageService;
final OnboardService onboardService;
CrewModel? _crew;
CrewModel? get crew => _crew;
bool get isAuth {
return _crew != null && _crew!.qrcodePayload.isNotEmpty;
}
Future<bool> authenticateCrewMember({required String qrCodePayload}) async {
log('AUTHENTICATING CREW MEMBER...');
try {
CrewModel? crew = await onboardService.authenticateCrewMember(
qrCodePayload: qrCodePayload,
);
if (crew == null) {
throw AppException('O QRCode apresentado não retornou dados.');
}
_crew = crew.copyWith(qrcodePayload: qrCodePayload);
await saveLocalData(_crew!);
log('[RESPONSE:PRD] - AUTH-CREW-MEMBER: _crew: $_crew');
notifyListeners();
return true;
} catch (e, s) {
log('[ERROR:PRD] - AUTH-CREW-MEMBER - $e, $s');
throw AppException('$e');
}
}
Future<void> saveLocalData(CrewModel crew) async {
log('saving data');
try {
await storageService.write(
key: STORAGE_CREW_AUTH_KEY,
value: crew.toJson(),
);
log('data saved');
} catch (e, s) {
log('save error: $e, $s');
}
}
}
AuthProviderTest
class MockStorageService extends Mock implements StorageService {}
class MockOnboardService extends Mock implements OnboardService {}
void main() {
late StorageService storageService;
late OnboardService onboardService;
late AuthProvider authProvider;
setUp(() {
storageService = MockStorageService();
onboardService = MockOnboardService();
authProvider = AuthProvider(
storageService: storageService,
onboardService: onboardService,
);
});
tearDown(() {
resetMocktailState();
});
group('AuthProvider.saveLocalData -', () {
*** this test passes ***
test('should call saveLocalData and return void when successful', () async {
final tModel = CrewModel.empty();
when(() => storageService.write(
key: STORAGE_CREW_AUTH_KEY,
value: tModel.toJson(),
)).thenAnswer((_) => Future.value(true));
await authProvider.saveLocalData(tModel);
verify(() => storageService.write(
key: STORAGE_CREW_AUTH_KEY,
value: tModel.toJson(),
)).called(1);
});
});
group('AuthProvider.authenticateCrewMember -', () {
test(
'should call authenticateCrewMember and return a CrewModel when successful',
() async {
const qrCodePayload = 'xxx';
final tModel = CrewModel.empty();
when(() => onboardService.authenticateCrewMember(
qrCodePayload: qrCodePayload))
.thenAnswer((_) => Future.value(tModel));
*** this throws the error ***
when(() => storageService.write(
key: STORAGE_CREW_AUTH_KEY,
value: tModel.toJson(),
)).thenAnswer((_) => Future.value(true));
final result = await authProvider.authenticateCrewMember(
qrCodePayload: qrCodePayload);
expect(result, true);
expect(authProvider.crew, isNotNull);
expect(authProvider.crew?.qrcodePayload, qrCodePayload);
verify(() => onboardService.authenticateCrewMember(
qrCodePayload: qrCodePayload)).called(1);
verifyNoMoreInteractions(onboardService);
*** this test does not pass because it is not called ***
verify(() => storageService.write(
key: STORAGE_CREW_AUTH_KEY,
value: tModel.toJson(),
)).called(1);
verifyNoMoreInteractions(storageService);
});
});
}
Thats the error when I run debug in the test
type 'Null' is not a subtype of type 'Future<bool>', #0 MockStorageService.write (file:///Users/XXX/Dev/YYY/my-app/test/provider/auth.provider_test.dart:11:7)
#1 AuthProvider.saveLocalData (package:my-app/provider/auth.provider.dart:148:28)
#2 AuthProvider.authenticateCrewMember (package:my-app/provider/auth.provider.dart:60:13)
<asynchronous suspension>
#3 main.<anonymous closure>.<anonymous closure> (file:///Users/XXX/Dev/YYY/my-app/test/provider/auth.provider_test.dart:109:22)
<asynchronous suspension>
#4 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:215:9)
<asynchronous suspension>
#5 Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:213:7)
<asynchronous suspension>
#6 Invoker._waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:258:9)
<asynchronous suspension>
any help will be very much appreciated.. cheers
forgot:
Flutter doctor
[✓] Flutter (Channel stable, 3.16.0, on macOS 13.2.1 22D68 darwin-arm64, locale en-BR)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.1)
[✓] VS Code (version 1.87.2)
[✓] Connected device (3 available)
[✓] Network resources
flutter_secure_storage: ^9.0.0
mocktail: ^1.0.3
If anyone is still having this issue can you please provide a link to a minimal reproduction sample? it's much easier for me to help if I'm able to reproduce the issue locally, thanks!
Hello, could someone suggest me an idea how to solve this? When im trying to mock flutter secure storage i get this error " type 'Null' is not a subtype of type 'Future<String?> "
-This is my storage
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
abstract class IStorage { Future saveData(String value, String key);
Future getId(String key);
}
class MyStorage implements IStorage { MyStorage(this._storage); final FlutterSecureStorage _storage; @override Future getId(String key) async {
return await _storage.read(key: key) ?? 'No data founded';
}
@override Future saveData(String value, String key) async {
await _storage.write(key: key, value: value);
}
}
-My Service
import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:fixed/shared/storage.dart'; import 'package:flutter/cupertino.dart';
class ApiService { final String _baseURL = 'https://jsonplaceholder.typicode.com/'; Dio _dio = Dio(BaseOptions()); final IStorage _storage;
ApiService(this._storage, {Dio? dio}) { _dio = dio ?? Dio(); _dio.options.baseUrl = _baseURL; }
Future get() async {
String id = await _storage.getId('id');
final response = await _dio.get('${_baseURL}posts/$id');
debugPrint(json.encode(response.data));
return json.encode(response.data);
}
}
My Test File
import 'package:dio/dio.dart'; import 'package:fixed/api/api_service.dart'; import 'package:fixed/shared/storage.dart'; import 'package:fixed/store/store1.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http_mock_adapter/http_mock_adapter.dart'; import 'package:mocktail/mocktail.dart';
class MockStorage extends Mock implements IStorage {}
class MockStorage2 extends Mock implements MyStorage {}
class MockFlutterSecureStorage extends Mock implements FlutterSecureStorage {}
void main() { final dio = Dio(); final dioAdapter = DioAdapter(dio: dio, matcher: const UrlRequestMatcher()); late ApiService service; late MockFlutterSecureStorage mockSecureStorage;
setUp(() { mockStorage = MockStorage(); mockSecureStorage = MockFlutterSecureStorage(); dio.httpClientAdapter = dioAdapter; service = ApiService(dio: dio, MyStorage(mockSecureStorage)); });
void mockData() { dioAdapter.onGet('https://jsonplaceholder.typicode.com/posts/1', (request) { return request.reply(200, {'data': 'sucessfull'}); }); }
void mockGetId() { when(() => mockStorage.getId('id')) .thenAnswer((invocation) => Future.value('1')); }
group('Test Service', () { test('Test endpoint', () async { //IT THROW ERROR when(() => mockSecureStorage.read(key: 'íd')).thenAnswer((_) async => ''); final data = await service.get(); expect(data, equals('{"data":"sucessfull"}')); verify(() => mockSecureStorage.read(key: 'id')).called(1); });
}); }