Dart/Flutter: Use a 'final' variable, that is loaded asynchronously - flutter

I am running into an issue regading using a final variable that is still loaded in asynchronously still after initializing, hence throwing a 'Re-initializing Exception'. The problem is that I am initializing a final instance of class A inside of class B. But the classA's contructor seems to be doing some async work as well. As a result (seems to be the case after debugging), that the required arguments of classA are the only ones initialized when the instance is created. And when the rest of attributes of classA are initialized async, it tries remodifying the instance, throwing an Exception. The skeleton looks like:
class classA {
_mainAttribute;
_otherAttributes . . .;
//getters . . .
classA (this.mainAttribute) {
// async call
_waitForJsonParse().then((_jsonRoot) {
// initialize _otherAttributes;
}
}
Future _waitForJsonParse() async {
return await . . .;
}
}
class classB {
late final List<classA> _errorCausingAttr;
classB () {
// another async call
_loadAssetManifest().then((manifestMap) {
_errorCausingAttr = List.unmodifiable(
mainfestMap.getFolders()
.map((String folderName) => classA(folderName.someValue())
);
// Exception occurs here: "LateInitializationError:
//Field '_errorCausingAttr#33137322' has already been initialized.".
}
}
Future _loadAssetManifest() async {
return await . . .;
}
}
My first solution was to not use 'final' variables then. But is there a way to do it without sacrficing the kind of declaritive schemes? Maybe there is a better pattern / there is a code smell here?

Related

Best way to get value from future in constructor in dart

what ways you suggest for getting value from future in object constructor ?
class F{
late SomeObj<t> _obj;
F(){
() async{
_obj = await someFuture();
}.call();
}
somefunc() => doing something with _obj
}
but this doesn't gave me right res in the right time,
Other ways for this situation?
Here are two possible approaches:
Make your class's constructor private and force callers to instantiate your class via an asynchronous static method. From the perspective of callers, there is little difference between calling a static method and a named constructor.
class F {
late SomeObj<T> _obj;
F._();
static Future<F> create() async {
var f = F._();
f._obj = await someFuture();
return f;
}
Object? someFunc() => doSomethingWith(_obj);
}
Explicitly make everything that depends on the asynchronous value also asynchronous. If _obj is initialized asynchronously, then _obj should be a Future. If someFunc depends on _obj, then someFunc should return a Future.
class F {
Future<SomeObj<T>> _obj;
F() : _obj = someFuture();
Future<Object?> someFunc() async => doSomethingWith(await _obj);
}

How to verify a method inside a method is called in mockito

I was doing some unit testing in flutter with mockito, and I feels unable to verify a method is called within another method. The code I've written so far as follows,
The class I want to test
class A {
void doSomething() {
callMe();
}
void callMe() {}
}
Mocked class
class MockA extends Mock implements A {}
The test I wrote,
test("Test method is called", () {
A a = new MockA();
a.doSomething();
verify(a.callMe()).called(1);
});
When I run the above test I am getting an error
No matching calls. All calls: MockA.doSomething()
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
If i verify doSomething is called it works, but for a call on callMe within doSomething doesn't work. Is this the default behavior or am I doing something wrong? Please note I need to verify the callMe() method is called when doSomething() is called.
You mocked A and replaced it with MockA. Mocks have no implementation. MockA.doSomething() does nothing and does not and cannot call MockA.callMe().
That A.doSomething() calls A.callMe() should be considered an implementation detail of of doSomething(); making a test rely on that would tightly couple the test to the specific implementation and would be brittle.
You can't use a mock to verify the implementation of the thing being mocked. If you want to verify the implementation of A.doSomething(), you instead should use an actual object and verify observable properties on that object.
But if you still really want to do this, then you would need to modify A to not call methods on itself and to instead call methods on a provided object (i.e., "dependency injection"). For example:
class A {
final late A a;
A({A? a}) {
this.a = a ?? this;
}
void doSomething() {
a.callMe();
}
void callMe() {}
}
test("Test method is called", () {
var mockA = MockA();
var actualA = A(a: mockA);
actualA.doSomething();
verify(mockA.callMe()).called(1);
});
It's a bit unusual for a class to depend on a mock of itself, however, and it would not scale if you then want to verify calls made by callMe().
Another approach that would scale better (but with significantly more work) would be to create your own fake class that tracks method calls:
class TrackedA implements A {
int doSomethingCallCount = 0;
int callMeCallCount = 0;
#override
void doSomething() {
doSomethingCallCount += 1;
super.doSomething();
}
#override
void callMe() {
callMeCallCount += 1;
super.callMe();
}
}
But again, that's very brittle, and I would not recommend it.

Override/mock library functions for dart/flutter testing

I was wondering if there is a way to override library functions so they don't fire or just return something else.
import 'package:foo_package/exposing_foo_function.dart';
class TestableClass {
bool bar() {
return foo(); //foo is from the imported library
}
}
Test:
void main() {
test('TestableClass.bar() when foo_package.foo() returns false', () {
TestableClass testableClass = TestableClass();
// Something to make foo_package.foo() return false.
expect(testableClass.bar(), isFalse);
});
}
Things like mockito work by creating mock classes that implement the interface of the mocked class. That doesn't work for global and static functions, however.
What you instead can do is to avoid calling those global/static functions directly and instead call them through an extra level of indirection. For example:
import 'package:foo_package/exposing_foo_function.dart' as foo_package;
class TestableClass {
final bool Function() foo;
TestableClass({this.foo = foo_package.foo});
bool bar() {
return foo();
}
}
and then to test:
void main() {
test('TestableClass.bar() when foo_package.foo() returns false', () {
bool fakeFoo() => false;
TestableClass testableClass = TestableClass(foo: fakeFoo);
expect(testableClass.bar(), isFalse);
});
}
A similar approach is to wrap the global/static functions as instance methods of a class:
import 'package:foo_package/exposing_foo_function.dart' as foo_package;
class FooManager {
bool foo() => foo_package.foo();
}
var fooManager = FooManager();
class TestableClass {
bool bar() {
return fooManager.foo();
}
}
and then your tests can mock FooManager like any other class and set fooManager to the mocked version. (Or if you prefer dependency inversion to global variables, passing your mocked version of FooManager to TestableClass as a construction argument.)
Of course, all of the above will help only for your own calls that go through your wrappers. It won't help if code you don't control calls those functions. In that case, your best course of action might be to complain to the function's author about lack of testability.

ReactiveX and Dart

I have a class Too
class Too{
bool isLogged = false;
BehaviorSubject suject = BehaviorSubject<bool>();
Too({required this.isLogged}){
suject = new BehaviorSubject<bool>.seeded(isLogged);
}
void login(){
isLogged = true;
suject.sink.add(isLogged);
}
void logOut(){
isLogged = false;
suject.sink.add(isLogged);
}
void dispose(){
suject.close();
}
and I also have the Foo class:
class Foo{
Too _too = new Too(isLogged: false);
_too.stream.listen((event) { print('${event}');});
}
My issue is When the user is calling the login() method of the Too class nothing happens at the level of the Foo class.
What I want to do is that if the user calls the login() method of the Too class and his isLogged attribute is set to true, then this change is done at the level of all the classes that have an attribute of the Too type.
Note: It's much easier to do it with Angular or Ionic using RxJS, but with dart, I don't know how to implement this mechanism.
Foo is not reacting because its listening to a different instance of Too.
The way you have it is that each new instance of Foo creates a new instance of Too. If I understand you correctly, you want all instances of Foo to react to any change to a single instance of Too.
You can use a singleton for this.
class Too {
// one of a few ways to make a singleton in Dart
Too._();
static final _instance = Too._();
factory Too() {
return _instance;
}
final subject = BehaviorSubject<bool>.seeded(isLogged);
static bool isLogged = false;
void login() {
isLogged = true;
subject.sink.add(isLogged);
}
void logOut() {
isLogged = false;
subject.sink.add(isLogged);
}
void dispose() {
subject.close();
}
}
Now you can have any Foo object listen to the same Too instance.
class Foo {
Foo() {
Too().subject.stream.listen((event) {
print('foo $event'); // this will now print whenever a subject from your Too class is updated.
});
}
}
Now for example you could test this by creating a button with this as the onPressed.
onPressed: () {
final foo = Foo(); // just created an example of a Foo object that will
// print the updated value of the Too singleton
Too().login();
},
RxDart is great. However when it comes to reactive programming in Flutter, I suggest checking out Get X as it simplifies a lot of stream based stuff.

async/await problem when extend super class

I need to set the order of execution of my methods on the constructor of my supper class because i have a multiple class that extends from this supper class and the order is the same on all of them (take advantage of abstract class), but i am facing a strange problem where i get a result of a variable before the finishing of the future, this is a simulation code of my above description, you can try it on dartpad.dev:
abstract class SuperClass {
bool _success;
bool get isSuccess => _success;
set setSuccess(bool success) => this._success = success;
SuperClass() {
//checkLogin();
runCode();
//sendRequest();
}
runCode() async {
await doSomething();
}
Future<void> doSomething();
}
class SubClass extends SuperClass {
String text;
#override
Future<void> doSomething() async {
text = await Future.delayed(Duration(seconds: 2), () => '2 sec of getting data');
if (text.isNotEmpty) {
setSuccess = true;
print(text);
}
print('value of success is "$isSuccess" from the overriding method');
}
}
void main() async {
SubClass subClass = new SubClass();
// if (subClass.isSuccess) // how can i get success from the sub class
// do somthing else
print('value of success is "${subClass.isSuccess}"');
}
the result is :
value of success is "null"
2 sec of getting data
value of success is "true" from the overriding method
My question is why i get the value of the variable from the super class while i am running the future method before it and read it from the sub class ?
Did i miss something or how i can handle this logic ?
you need another method in the abstract class, when creating an object from the subclass, calling abstract class constructor automatically, you are calling "doSomething" override method in the constructor by "runCode" method, but since "doSomething" method is override method It will be called automatically in subclasses, So you need another method
If your question is about why you get the print in this order rather than:
2 sec of getting data
value of success is "true" from the overriding method
value of success is "true"
that is just because you call the async function runCode() in the constructor of SuperClass which is implicitly called when you create a SubClass as the latter inherits from the former. Since the method is async and you are not awaitint it, the method starts running on a different thread and code execution is not stoped there waiting for the runCode() method to return.
This means that runCode() starts executing in a different thread and immediately after that, the SuperClass constructor returns, the SubClass method (which implicitly called the former) also returns, and then your print statement from main executes. Since these steps take less than two seconds to execute, they finish executing before the rest of runCode()
Instead, you can remove the runCode() from the abstract class constructor and call the doSomething() method after initializing:
void main() async {
SubClass subClass = new SubClass();
await subClass.doSomething();
print('value of success is "${subClass.isSuccess}"');
}