dart throw fake stacktrace in a test

Viewed 143

Is it possible to throw a fake stack trace in dart? For example, I have this code:

      final FakeStartContext startContext = FakeStartContext(
        runOverride: () async => throw Exception(fakeError),
      );

It is overriding a function by throwing a fake exceptionMsg to it. Is there a way to throw a fake stack trace in addition to the fake error as well? Like something similar to this:

      final FakeStartContext startContext = FakeStartContext(
        runOverride: () async => throw Exception(fakeError, fakeStackTrace),
      );

Such that it could be caught by catch(err, stacktrace)?

2 Answers

You can, because your code is asynchronous:

final FakeStartContext startContext = FakeStartContext(
  runOverride: () async => 
      await Future.error(Exception(fakeError), fakeStackTrace),
);

or just

final FakeStartContext startContext = FakeStartContext(
  runOverride: () => Future.error(Exception(fakeError), fakeStackTrace),
);

It's not currently possible to do the same thing in a synchronous setting. It doesn't help to to create a future containing your fake stack trace, because you can't wait for that future synchronously.

As mentioned, an Error.throwWithStackTrace(error, stack) function is scheduled to be added in Dart 2.16, which can synchronously throw an object and a stack trace of your choice.

Why use a fake stacktrace when you can easily get a real one?

For example:

thrower() {
  ghi() => throw Exception('error');
  def() => ghi();
  abc() => def();
  abc();
}

void main() {
  try {
    thrower();
  } catch (e, st) {
    print('Error $e, StackTrace: $st');
  }
}

This will print something like this on Dart VM:

Error Exception: error, StackTrace: #0      thrower.ghi (file:///Users/renato/example.dart:2:12)
#1      thrower.def (file:///Users/renato/example.dart:3:15)
#2      thrower.abc (file:///Users/renato/example.dart:4:15)
#3      thrower (file:///Users/renato/example.dart:5:6)
#4      main (file:///Users/renato/example.dart:10:5)
#5      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
#6      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

On dartpad.dev (JS) it prints this instead:

Error Exception: error, StackTrace: wrapException@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:363:17
throwExpression@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:377:15
call$0@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:3040:16
call$0@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:3046:23
call$0@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:3052:23
thrower@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:272:65
main@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:277:11
@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:3217:15
@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:3200:15
dartProgram@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:3211:5
@https://dartpad.dev/scripts/frame_dark.html line 19 > injectedScript:3219:3
replaceJavaScript@https://dartpad.dev/scripts/frame.js:19:19
messageHandler@https://dartpad.dev/scripts/frame.js:140:30
Related