0

The following code is a simplification of the code that I have and may not disclose:

class Logger {
    var _loggingStarted = false;

    void startLogging() {
        if (!_loggingStarted) {
            _loggingStarted = true;
            print('Logging started');
        } else {
            throw StateError('Logging has already been started');
        }
    }

    bool get loggingStarted => _loggingStarted;

    void log(String message) {
        if (_loggingStarted) {
            print(message);
        } else {
            throw StateError('Logging has not been started yet');
        }
    }

    void stopLogging() {
        if (_loggingStarted) {
            _loggingStarted = false;
            print('Logging stopped');
        } else {
            throw StateError('Logging has not been started yet');
        }
    }
}

void main() {
    test('Testing class Logger', () async {
        final instance = Logger();
        await expectLater(() => instance.log('Message'), allOf(prints(''), throwsStateError)); // This gives me currently a NoSuchMethodError
    });
}

How can I check that the function log throws a StateError and prints nothing to the console in the same expect / expectLater statement?

Or is there no way around writing a relatively long callback like the following?

await expectLater(() {
    try {
        instance.log('Message');
        fail('The call to function log must throw a StateError, but did not throw anything');
    } on StateError {
        return;
    } on Object catch (error) {
        fail('The call to function log must throw a StateError, but threw a(n) ${error.runtimeType.toString()}'); 
    }
}, prints(''));

The NoSuchMethodError that I currently get is printed like the following to the Test Results window in Visual Studio Code:

NoSuchMethodError: The method 'describeMismatch' was called on null.

Receiver: null

Tried calling: describeMismatch(Closure: () => void, Instance of 'StringDescription', null, false)

package:matcher expectLater

package:flutter_test/src/widget_tester.dart 508:8 expectLater

<File name>.dart <Line no>:13 main.<fn>

1 Answer 1

2

You can’t combine prints(...) and throwsStateError in a single matcher like allOf(...) because prints requires the closure to complete without throwing. Instead, nest the throw assertion inside a closure that prints wraps, so the exception is caught by the inner expect and doesn’t escape.

Do this

test('Logger.log throws and prints nothing', () async {
  final instance = Logger();

  await expectLater(
    () {
      // This asserts the throw and prevents it from escaping,
      // so `prints('')` can still verify no output.
      expect(() => instance.log('Message'), throwsStateError);
    },
    prints(''),
  );
});
  • Why this works: prints captures output from its closure and fails if that closure throws. By asserting the throw inside the closure, the exception is handled by the inner expect, so the outer prints('') can verify that nothing was printed.

  • prints('') checks that nothing was printed. You could also use prints(isEmpty).

  • Avoid allOf(prints(...), throws...) with functions that are expected to throw; it leads to matcher conflicts (and the NoSuchMethodError you saw).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.