How to mock a static method in Flutter with Mockito? How to mock a static method in Flutter with Mockito? flutter flutter

How to mock a static method in Flutter with Mockito?


Eventually, I had to rewrite my database.dart to make it testable / mockable.
Here's the new file:

import 'dart:async';import 'package:path/path.dart';import 'package:sqflite/sqflite.dart';class DBProvider {  static final DBProvider _singleton = DBProvider._internal();  factory DBProvider() {    return _singleton;  }  DBProvider._internal();  static Database _db;  static Future<Database> _getDatabase() async {    if (_db != null) return _db;    // if _database is null, we instantiate it    _db = await _initDB();    return _db;  }  static Future<Database> _initDB() async {    final dbPath = await getDatabasesPath();    String path = join(dbPath, 'demo.db');    return openDatabase(path, version: 1, onCreate: _onCreate);  }  Future<String> insert(String table, Map<String, dynamic> values) async {    final db = await _getDatabase();    return db.insert(table, values);  }  // ...}

Now I can use the same trick as with the http.Client.Thank you @RĂ©miRousselet


Let's say we want to test [TargetClass.someMethodCallOtherStaticMethod]

Class StaticMethodClass {  static int someStaticMethod() {};}Class TargetClass {  int someMethodCallOtherStaticMethod() {    return StaticMethodClass.someStaticMethod();  }}

We should refactor [[TargetClass.someMethodCallOtherStaticMethod]] for testing,like this:

Class TargetClass {  int someMethodCallOtherStaticMethod({@visibleForTesting dynamic staticMethodClassForTesting}) {    if (staticMethodClassForTesting != null) {      return staticMethodClassForTesting.someStaticMethod();    } else {      return StaticMethodClass.someStaticMethod();    }          }}

Now you can write your test case like this:

// MockClass need to implement nothing, just extends MockMockClass extends Mock {}test('someMethodCallOtherStaticMethod', () {  // We MUST define `mocked` as a dynamic type, so that no errors will be reported during compilation  dynamic mocked = MockClass();  TargetClass target = TargetClass();  when(mocked.someStaticMethod()).thenAnswer((realInvocation) => 42);  expect(target.someMethodCallOtherStaticMethod(staticMethodClassForTesting: mocked), 42); }) 


The question was some while ago, but here is another solution. You can refactor calls to that static function to be called from a class "wrapper" method. This is a pattern I often use to mock requests to third party services.

Let me give you an example. To make it simple lets say Engine has 3 static methods that need to be mocked: brake() and accelerate() and speed().

class Car {    int currentSpeed;    void accelerateTo(int speed) {         while(currentSpeed > speed) {              Engine.brake();              currentSpeed = Engine.speed();         }         while(currentSpeed < speed) {              Engine.accelerate();              currentSpeed = Engine.speed();         }    }}

Now you want to mock all calls to the engine, to do so we could refactor the code to:

class Car {    int currentSpeed;    void accelerateTo(int speed) {         while(currentSpeed > speed) {              brake();              currentSpeed = speed();         }         while(currentSpeed < speed) {              accelerate();              currentSpeed = speed();         }    }    /// wrapper to mock Engine calls during test    void brake() {        Engine.brake();    }    /// wrapper to mock Engine calls during test    int speed() {        Engine.speed();    }    /// wrapper to mock Engine calls during test    void accelerate() {        Engine.accelerate();    }}

In the integration test you can now mock the 3 methods that interact with the static methods directly but you can now test your main method. While you could here also refactor the Engine class itself, often that class would be within a third party service.

This example is not based on the Volkswagen scandal ;).