How to create mockito object from flutter singleton class? - flutter

I'm trying to write unit tests for my flutter application. I'm using the Mockito package. I had some problem with the null safety requirement for the new flutter versions. The Mockito requires the new flutter version but lots of other packages I use are incompatible, so I just put the // #dart=2.9 on top of all my files. Not sure if that could be source of some problems.
So here I would like to test that when the onPressedSubmit method is called on the SliderRatingPage (that's what happens when the user taps a certain button), that the application will call the database. Specifically it should call the insertRow method defined in the DatabaseHelper class.
Here I would expect that annotating the test case with #GenerateMocks([DatabaseHelper]) will effectively mock out every call to DatabaseHelper class, therefor I could use verify to test that the insertRow method was called, just as is written in the code below. But the DatabaseHelper is apparently a non-mockito object, as that is the error message I get when trying to run the test.
What is then the correct way to write a test that would do what I intended?
// #dart=2.9
import 'package:test/test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:my_app/uidesign/page_slider_rating.dart'; //SliderRatingPage class
import 'package:my_app/database/database_helpers.dart'; //DatabaseHelper class, singleton
#GenerateMocks([DatabaseHelper])
void main() {
test('onPressedSubmit calls database.', () async {
SliderRatingPage page = SliderRatingPage();
page.createState().onPressedSubmit();
verify(DatabaseHelper.instance.insertRow(any));
});
}

Related

Eclipse IDE don't import static Mockito method

I write simple test, where is mockito static method like verify, times, any.
And problem next, i can not import this method automatically or click to method and chose Import,
i can only write in the top of my class import static org.mockito.Mockito.verify; or import static org.mockito.Mockito.test;

Mocking classes or global functions in flutter/dart

I am trying to understand how mocking works with dart and mockito.
Image I have the below declarations:
void foo(){}
and similarly a class
class BarClass {
void bar(){}
}
and then my widget accesses the first one directly as foo(); and the second one as BarClass().
What would be the way to mock these two? Should I be accessing them through something like getit to mock them properly or is there actually a way?
You can easily mock classes by creating a new class that implements the functionality of your old one using the mockito package
example code:
class MockBarClass extends Mock implements BarClass {}
you can mock methods of your BarClass in the following way:
final mock = MockBarClass();
when(() => mock.boo()).thenAnswer((_) {
// your mocked response
print("hello world");
});
you can mock functions that are in no classes the same way:
when(boo()).thenReturn();
source by Remi Rousselet
additional information if you ask yourself what's the difference between .thenReturn(...) and .thenAnswer((){...}):
I recommend reading this explanation: https://stackoverflow.com/a/36627077/12165405 (even though it's for java, the same applies for that flutter package)

How to import Dart file or package dependent on Flutter platform?

My goal is to import platform-specific code only on the respective platform. One use case is e.g. if the dart:html package is used in the imported file which isn't available on iOS. Another example for platform-specific Dart code: XHR HTTP request (only available in browser) vs. other HTTP client implementation.
Previous, failed attempts:
1)
import 'specific_to_web.dart' if (dart.library.html) '';
2)
import 'package:flutter/foundation.dart' show kIsWeb;
import 'specific_to_web.dart' if (kIsWeb) '';
3)
In the file I'm importing:
export 'api_channel_grpc_web.dart'
if (dart.library.html) 'api_channel_grpc_raw.dart';
This is also mentioned in Flutter issue Dart SDK libraries and Flutter for web.
The really clean and sustainable solution is to write a federated plugin. Plugins are not just for external use, for other people to consume as a library, you can easily put a plugin inside your own project to separate out platform specific code.
If you really don't want to do that because you only need a few items inside your own code, just set up the usual interface-implementation approach. You write an abstract class with the interface you want to use, you write two (or more) implementations and you include the one you need conditionally. An extract from one of my apps:
The interface:
// interface.dart
import 'worker.dart' //
if (dart.library.io) 'worker_io.dart'
if (dart.library.html) 'worker_async.dart';
abstract class BackgroundWorker {
factory BackgroundWorker() => getWorker();
void sendTo(dynamic message);
}
The base implementation:
// worker.dart
BackgroundWorker getWorker() => throw UnimplementedError('getWorker');
The mobile implementation:
// worker_io.dart
BackgroundWorker getWorker() => BackgroundWorkerIo();
class BackgroundWorkerIo implements BackgroundWorker {
#override
void sendTo(dynamic message) {
}
}
The web implementation:
// worker_web.dart
BackgroundWorker getWorker() => BackgroundWorkerWeb();
class BackgroundWorkerWeb implements BackgroundWorker {
#override
void sendTo(dynamic message) {
}
}
To use it, you simply call getWorker(), that will return the actual implementation needed, and you call its methods, functions, fields, whatever.
Oh, and while I didn't need it in this code of mine but if the implementations are not that lightweight and you want to avoid instantiating them again and again with every call to getWorker(), return a singleton instead.

With Play framework what am I doing wrong in setting up my routers

I'm a newbie to Play and Scala (version 2.6) and I can't figure out how to get the routing to work in a simple fashion. Cobbling together examples from the 2.6 documentation I've manage to create a custom application loader, which I understand is required to perform Evolutions migrations. The example I found included a var router = Routes.empty The BuiltInComponentsFromContext appears to require a router to be used, but in doing so, with the way I've done it my routes are now broken and now all I get are "Action Not Found" messages.
Here is my application.conf:
play.application.loader=MyApplicationLoader
router = my.application.Router
Here is the Application Loader
import play.api.ApplicationLoader
import play.api.ApplicationLoader.Context
import play.api.BuiltInComponentsFromContext
import play.api.db.{Database, DBComponents, HikariCPComponents}
import play.api.db.evolutions.EvolutionsComponents
import play.api.routing.Router
import play.filters.HttpFiltersComponents
//import com.softwaremill.macwire._
class MyApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new MyComponents(context).application
}
}
class MyComponents(cntx: Context)
extends BuiltInComponentsFromContext(cntx)
with DBComponents
with EvolutionsComponents
with HikariCPComponents
with HttpFiltersComponents
{
// this will actually run the database migrations on startup
//lazy val router = Router.empty
val router = Router.empty
applicationEvolutions
}
It looks to me by declaring:
val router = Router.empty
I'm essentially invalidating any of the routes I've declared in my conf/routes file, and it occurs to me to use the Router.load method, but I can't find an example of how to pass the required environment and configuration values to the method. Assuming I don't want to use static routes how do I do this?
Assuming that you only use compile-time dependency injection just for the sake of the Evolutions (because otherwise you'd faced the same problems earlier), the answer is that you don't have to do that. Evolutions work with the default dynamic dependency injection as well. The part of the documentation you probably basing your assumptions on actually says that if you are already using the compile-time dependency injection, here is how to modify it to make evolutions work. If you look at the source code of the EvolutionsModule you may see that ApplicationEvolutions is bound eagerly. It means that an instance of ApplicationEvolutions will be created at the start of the app during application initialization. And in the source code of the ApplicationEvolutions itself you can see that start() is called from the constructor. So if you provided configuration, the rest should work on its own.

Play 2.5.X dependency injection

I am upgrading play framework app from 2.4.6 to 2.5.x.
There are several occurrences where I call helper methods which belongs to some object. These helper methods use play's built-in classes(for example play.api.Play.current.configuration.underlying.getString) to get the job done.
I get following warning: "method current in object Play is deprecated: This is a static reference to application, use DI instead"
If I face this problem in class method then I can use dependency injection. How to deal with such a situation where method belongs to object and I am warned to use DI?
Play Framework usually provides a class you can inject instead of using the old static references.
For example, the below would mean you can stop using Play.current.configuration and DB:
import javax.inject.Inject
import play.api.db.Database
import play.api.Configuration
class MyClass #Inject() (configuration: Configuration, db: Database) {
...
}