in short, throwsA(anything) does not suffice for me while unit testing in dart. How to I test for a specific error message or type?
Here is the error I would like to catch:
class MyCustErr implements Exception {
String term;
String errMsg() => 'You have already added a container with the id
$term. Duplicates are not allowed';
MyCustErr({this.term});
}
here is the current assertion that passes, but would like to check for the error type above:
expect(() => operations.lookupOrderDetails(), throwsA(anything));
This is what I want to do:
expect(() => operations.lookupOrderDetails(), throwsA(MyCustErr));
This should do what you want:
expect(() => operations.lookupOrderDetails(), throwsA(isA<MyCustErr>()));
if you just want to check for exception check this answer:
As of April 2021 this is the correct method.
CORRECT METHOD
import 'package:dcli/dcli.dart';
import 'package:test/test.dart';
/// GOOD: works in all circumstances.
expect(() => restoreFile(file), throwsA(isA<RestoreFileException>()));
Some examples show :
INCORRECT METHOD
import 'package:dcli/dcli.dart';
import 'package:test/test.dart';
/// BAD: works but not in all circumstances
expect(restoreFile(file), throwsA(isA<RestoreFileException>()));
Note the missing '() => ' after the expect.
The difference is that the first method will work for functions that return void whilst the second method won't.
So the first method should be the prefered technique.
To test for a specific error message:
CHECK CONTENTS OF EXCEPTION AS WELL
import 'package:dcli/dcli.dart';
import 'package:test/test.dart';
expect(
() => copy(from, to),
throwsA(predicate((e) =>
e is CopyException &&
e.message == 'The from file ${truepath(from)} does not exists.')));
After `TypeMatcher<>' has been deprecated in Flutter 1.12.1 I found this to work:
expect(() => operations.lookupOrderDetails(), throwsA(isInstanceOf<MyCustErr>()));
In case anyone wants to test with an async function like I had to do all you need to do is add async keyword in the expect, bearing in mind that the lookupOrderDetails is an async function:
expect(() **async** => **await** operations.lookupOrderDetails(), throwsA(const TypeMatcher<MyCustErr>()));
expect(() **async** => **await** operations.lookupOrderDetails(), isInstanceOf<MyCustErr>()));
It still uses Gunter's answer which is very good!
First import correct package 'package:matcher/matcher.dart';
expect(() => yourOperation.yourMethod(),
throwsA(const TypeMatcher<YourException>()));
The current proper way to expect that a function call throws an exception is:
expect(operations.lookupOrderDetails, throwsA(isA<MyCustErr>()));`
Related
Debugging with extension methods seems to be a bit problematic currently.
Consider the following code:
import 'dart:developer';
void main() {
final a = A();
workaround = a.extMethod;
debugger();
a.normalMethod();
a.extMethod();
}
class A {
String normalMethod() => 'hello from class';
}
extension AX on A {
String extMethod() => 'hello from extension';
}
When debugging this, stepping into both methods (normalMethod() and extMethod()) will work fine, the only difference is that this isn't available for extMethod() for some reason (there is #this instead, but it can't be used anyhow).
The extension method (extMethod()) is impossible to use for evaluations in the debug console, though.
a.normalMethod()
"hello from class"
a.extMethod()
Unhandled exception:
NoSuchMethodError: Class 'A' has no instance method 'extMethod'.
Receiver: Instance of 'A'
Tried calling: extMethod()
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:38:5)
#1 Eval ()
workaround()
"hello from extension"
I have found kind of a workaround as you can see, but it has to be in place before running the program so I'd definitely prefer a better method that can be used on fly without any preparation.
I have found two very old issues describing this exact problem but both are closed and from what I understand, unresolved.
https://github.com/dart-lang/sdk/issues/44801
https://github.com/dart-lang/sdk/issues/44472
I'm using Dart 2.18.6 (latest stable).
I'm trying to create a simple debug/print function that I can pipe through a sequence of then while processing Future results in Dart.
My function definition is as follows:
import 'dart:async';
typedef FutureOr<T> Pipe<T>(T pipeThrough);
Pipe<A> debug<A>(String log) {
return (A pipeThrough) {
print(log);
return pipeThrough;
};
}
It will return a function that just pipes through whatever it has received from the Future chain, and before that it will print the message log that has been sent to debug.
The way I'm using the function is quite simple:
Future<Map> load(String folder) {
return File(Paths.of([folder, 'data.json']))
.readAsString()
.then((s) => jsonDecode(s))
.then(debug<Map>('JSON LOADED!'));
}
As you can see in the last then in the future chain, it is supposed to return whatever was in the chain, but before that print 'JSON LOADED!'.
But there is something with the generics and Future api that I didn't manage to find a way to make it work, here's the error:
Unhandled exception:
type '(Map<dynamic, dynamic>) => Map<dynamic, dynamic>' is not a subtype of type '(dynamic) => FutureOr<Map<dynamic, dynamic>>'
#0 load (file:///{.../..../......}/data/data_json.dart:11:13)
#1 main (file:///{.../..../......}/data/main.dart:7:28)
#2 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
I've tried a bunch of different things, but fundamentally I don't get what's happening, doesn't dart infer the proper types based on the generic types annotation?
I don't know why it can't handle the type here, but changing the code to
Future<Map> load(String folder) {
return File(Paths.of([folder, 'data.json']))
.readAsString()
.then((s) => jsonDecode(s))
.then((v) => debug<Map>('JSON LOADED!')(v));
}
fixes your issue. I had thought that this should be equivalent...
I have this function which plays a sound inside of Flutter using the audioplayer plugin.
play(int soundFrequency) async {
final result = await audioPlayer.play("urltosound.wav");
}
It works fine. But now I want to be able to play multiple sounds in a row. It seems as if I mess up with the futures. I tried this approach, which is very dirty and ugly but I was just trying to figure things out:
playRandomSequence() async {
final result = audioPlayer.play("urltosound.wav").then(play2(pickRandomSoundFrequency()));
}
play2(int soundFrequency) async {
final result = audioPlayer.play("urltosound.wav");
}
Basically, as soon as the first future is over, I call the next one with the .then() method.
What I get from it is this error:
type '_Future' is not a subtype of type '(dynamic) => dynamic' of 'f' where _Future is from dart:async
How can I fix this?
Thanks
You have the wrong type for the argument of .then(). Try:
.then((_) => play2(pickRandomSoundFrequency()))
You need to pass a function to be called, not call the function when constructing the arguments to then.
Good morning,
I've been trying to use the removeByName method and it doesn't work.
I'm basically trying to hide a field in my DataObject within the forms that's generated by ModelAdmin, which manages the object.
See sample code below:
///DataObject snippet...
class MyObject extends DataObject{
public static $db = array(
'Title' => 'Varchar',
'Desc' => 'Text',
'Template' => 'HTMLText',
);
//#Override
public function getCMSField(){
$fields = parent::getCMSField();
$fields->removeByName('Template'); /// DOESN'T WORK!!!
return $fields;
}
}//class
Note: I'm not getting any errors. I'm just still seeing the field on the forms (Add and Edit) as usual.
Any help appreciated, thanks.
Okay, I found the issue.
I was just going over the API again for the millionth time, and recognized that I've named the function wrong. See correction below:
///Correction, forgot to add the 's' at the end of both the function and the parent call.
public function getCMSFields(){
$fields = parent::getCMSFields();
}
I can understand an error not being generated in Apache logs for the function because it's legit. But as for the parent call, it should of generated an error since the method don't exists. (Theory: Perhaps, since the function was never actually being called, the parent call wasn't being executed and thus no errors [run-time error]).
The following code throws the exception "type '([int]) => void' is not a subtype of type 'RequestAnimationFrameCallback' of 'callback'."
import 'dart:html';
void main() {
window.animationFrame.then((time) => print("test"));
}
If I change window.animationFrame.then to window.requestAnimationFrame, everything works as expected. Am I misunderstanding how Dart futures work?
Usage looks right.
Either you are running an older version that doesn't yet implement the behavior that is specified in the documentation or it is simply a bug. I would go ahead and file an issue on http://dartbug.com/new