Тестирование исключений в Dart

При написании тестов для кода, который генерирует исключение, как Dart / Mockito(или что-то еще) может избежать генерации настоящего исключения? Например, эти тесты должны и проходить, и обнаруживать возникшее исключение, но Dart выдает реальное исключение в первом тесте, поэтому проходит только «Он получает Todo».

      void main() {
  test('It throws an exception', () async {
    final client = MockClient();
    when(client.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/1'))).thenAnswer((_) async => http.Response('', 404));
    expect(await fetchTodo(client, 1), throwsException);
  });

  test('It receives a Todo', () async {
    final client = MockClient();
    final jsonString = '''
    {
      "id": 1,
      "userId": 1,
      "title": "test",
      "completed": false
    }
    ''';
    when(client.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/2'))).thenAnswer((_) async => http.Response(jsonString, 200));
    expect(await fetchTodo(client, 2), isA<Todo>());
  });
}

и метод mocked get (на основе сгенерированного кода mockito - я получаю те же результаты при использовании @GenerateMocks([http.Client]) в моем тестовом файле.

      class MockClient extends Mock implements http.Client {
  Future<http.Response> get(Uri url, {Map<String, String>? headers}) {
    return super.noSuchMethod(Invocation.method(#get, [url], {#headers: headers}), returnValue: Future.value(http.Response('', 200))) as Future<http.Response>;
  }
}
      class Todo {
  int id;
  int userId;
  String title;
  bool completed;

  Todo(this.id, this.userId, this.title, this.completed);
}

Future<Todo> fetchTodo(http.Client client, int id) async {
  final response = await client.get(Uri.parse('https://jsonplaceholder.typicode.com/todos/$id'));

  if(response.statusCode == 200) {
    return Todo(1, 1, 'Test', true);
  }else {
    throw Exception('Failed to fetch resource');
  }
}

Отчет о тестовом запуске:

      00:00 +0: It throws an exception
00:00 +0 -1: It throws an exception [E]
  Exception: Failed to fetch resource
  test/test.dart 49:5  fetchTodo
  
00:00 +0 -1: It receives a Todo
00:00 +1 -1: Some tests failed.

1 ответ

Решение

Ваша проблема в том, что вы делаете:

       expect(await fetchTodo(client, 1), throwsException);

- обычная функция, и аргументы функции оцениваются перед вызовом функции. (Dart - это язык прикладного порядка .) Поэтому вы ждете завершения, прежде чем звонить expect() (а раньше можете попытаться сыграть против).

Как объяснил <tcode id="3425199"></tcode> документация (и это относится к throwsException Matcher тоже), он должен быть сопоставлен с функцией с нулевым аргументом или Future. Вам не нужно (и не следует) await призыв к fetchTodo.

Кроме того, поскольку вы вызываете асинхронную функцию, ожидание не может быть проверено синхронно, поэтому вам также необходимо использовать expectLater вместо expect:

      await expectLater(fetchTodo(client, 1), throwsException);
Другие вопросы по тегам