简体   繁体   中英

How to test class that is using flutter secure storage in flutter

I am using "flutter_secure_storage" package in my flutter app to store token for REST API. My Authentication class is given below:

import 'dart:convert';

import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart' as http;
import 'package:tutor_finder_frontend/constants/api_path.dart' as APIConstants;

class Auth {
  final _storage = FlutterSecureStorage();
  var headers = {'Content-Type': 'application/json'};

  Future<bool> isLoggedIn() async {
    final isLoggedIn = await _storage.containsKey(key: 'token');
    return isLoggedIn;
  }

  logOut() async {
    await _storage.delete(key: 'token');
  }

  Future<bool> createAccount(String email, String password) async {
    var body = jsonEncode({'email': email, 'password': password});
    var response = await http.post(Uri.parse(APIConstants.CREATE_USER_URL),
        headers: headers, body: body);

    if (response.statusCode == 201) {
      var jsonResponse = jsonDecode(response.body);
      var token = jsonResponse['token'];
      await _storage.write(key: 'token', value: token);
      return true;
    }
    return false;
  }

  Future<bool> logIn(String email, String password) async {
    var body = jsonEncode({'username': email, 'password': password});
    var response = await http.post(Uri.parse(APIConstants.LOGIN_USER_URL),
        headers: headers, body: body);

    if (response.statusCode == 200) {
      var jsonResponse = jsonDecode(response.body);
      var token = jsonResponse['token'];
      await _storage.write(key: 'token', value: token);
      return true;
    }
    return false;
  }
}

I want to test this class. I know about Mock and mockito package in flutter. But I can't figure out how to create mock for FlutterSecureStorage class.

For example, how would I call "logIn" function to store the token and then call "isLoggedIn" function to check if the token is there. Is this even possible? I know this may not be the usual use of Unit test. Should I even do this kind of test?

The key part is to inject the dependency to secure storage into Auth instead of declaring it as a class variable. Otherwise you cannot mock it.

I would solve it further by creating an interface through which I use secure storage, and pass the interface as a variable to Auth. That way it is easy to mock (and also replace) that plug-in if needed. Abstracting away the plug-in specific dependency can often be very good.

It's a good thing to test your login method. But remember that you should unit test YOUR code and not make sure that SecureStorage is doing its bit correctly. That responsibility is on the unit test of SecureStorage write method. Your unit test should make sure that secure storage's write method (or rather the interface saveToken method) is called once.

So something like this:

class Auth {
  Auth(this._storage);
  final IStorage _storage;
  ...
}

abstract class IStorage {
  Future<void> saveToken(String token);
}

class MyStorage implements IStorage {
  MyStorage(this._storage);
  final FlutterSecureStorage _storage;

  @override
  Future<void> saveToken(String token) => _storage.write(key: 'token', value: token);
}

This way your Auth class is not directly dependant on FlutterSecureStorage, you can easily mock IStorage and make sure that all is OK in Auth.

Your test can then do something like this:

class MockStorage extends Mock implements IStorage {}
final mockStorage = MockStorage();
final auth = Auth(mockStorage);
...
verify(() => mockStorage.saveToken()).called(1);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM