你如何在 Dart 中对异常进行单元测试?

Posted

技术标签:

【中文标题】你如何在 Dart 中对异常进行单元测试?【英文标题】:How do you unittest exceptions in Dart? 【发布时间】:2012-10-29 05:39:10 【问题描述】:

考虑一个根据传递的参数进行一些异常处理的函数:

List range(start, stop) 
    if (start >= stop) 
      throw new ArgumentError("start must be less than stop");
    
    // remainder of function

如何测试是否引发了正确类型的异常?

【问题讨论】:

【参考方案1】:

在这种情况下,有多种方法可以测试异常。简单地测试是否引发了非特定异常:

expect(() => range(5, 5), throwsException);

测试是否引发了正确类型的异常:

有几个用于一般用途的预定义匹配器,例如throwsArgumentErrorthrowsRangeErrorthrowsUnsupportedError 等。对于不存在预定义匹配器的类型,您可以使用TypeMatcher<T>

expect(() => range(5, 2), throwsA(TypeMatcher<IndexError>()));

确保不引发异常:

expect(() => range(5, 10), returnsNormally);

测试异常类型和异常信息:

expect(() => range(5, 3), 
    throwsA(predicate((e) => e is ArgumentError && e.message == 'start must be less than stop')));

这是另一种方法:

expect(() => range(5, 3), 
  throwsA(allOf(isArgumentError, predicate((e) => e.message == 'start must be less than stop'))));

(感谢 Google 的 Graham Wheeler 提供最后 2 个解决方案)。

【讨论】:

我在做expect(range(5, 3), throwsArgumentError),但在期望中没有捕获到异常。期望的第一个参数必须是一个匿名函数,在调用时最终会抛出。您的回答帮助我找到了那个愚蠢的错误,谢谢! 同时 new isInstanceOf&lt;ArgumentError&gt;() 已被弃用。应该使用 TypeMatcher:例如throwsA(TypeMatcher&lt;Exception&gt;()) 使用 TypeMatcher 似乎不再有效。有效的是throwsA(isA&lt;Exception&gt;()) 这绝对是最好的答案,但我想知道为什么对于如此简单的任务语法必须如此冗长.. 你不能没有闭包来进行测试,但是如果你需要这么多时间,可以考虑为更简洁的代码创建一个自定义匹配器。【参考方案2】:

我喜欢这种方法:

test('when start > stop', () 
  try 
    range(5, 3);
   on ArgumentError catch(e) 
    expect(e.message, 'start must be less than stop');
    return;
  
  throw new ExpectException("Expected ArgumentError");  
);

【讨论】:

它比其他选项更冗长,但它的可读性很强,而且它并不假设你已经记住了整个 unittest 库;)【参考方案3】:

作为@Shailen Tuli 的提议的更优雅的解决方案,如果您希望在特定消息中出现错误,您可以使用having

在这种情况下,您正在寻找这样的东西:

expect(
  () => range(5, 3),
  throwsA(
    isA<ArgumentError>().having(
      (error) => error.message,        // The feature you want to check.
      'message',                       // The description of the feature.
      'start must be less than stop',  // The error message.
    ),
  ),
);

【讨论】:

【参考方案4】:

使用throwsATypeMatcher 检查异常。

注意:isInstanceOf 现已弃用。

List range(start, stop) 
    if (start >= stop) 
      throw new ArgumentError("start must be less than stop");
    
    // remainder of function



test("check argument error", () 
  expect(() => range(1, 2), throwsA(TypeMatcher<ArgumentError>()));
); 

【讨论】:

我错过了 expect() 方法的 () => sintaxe。谢谢。【参考方案5】:

虽然其他答案肯定是有效的,但像 TypeMatcher&lt;Type&gt;() 这样的 API 现在已弃用,您必须使用 isA&lt;TypeOfException&gt;()

例如,以前是什么,

expect(() => range(5, 2), throwsA(TypeMatcher<IndexError>()));

现在是

expect(() => range(5, 2), throwsA(isA<IndexError>()));

【讨论】:

【参考方案6】:

对于简单的异常测试,我更喜欢使用静态方法API:

Expect.throws(
  // test condition
  () 
    throw new Exception('code I expect to throw');
  ,
  // exception object inspection
  (err) => err is Exception
);

【讨论】:

它对我不起作用。似乎 Expect.throws() 被删除了。【参考方案7】:

我使用了以下方法:

首先你需要将你的方法作为一个 lambda 传递给期望函数:

expect(() => method(...), ...)

其次,您需要将throwsAisInstanceOf 结合使用。

throwsA 确保抛出异常,使用isInstanceOf 您可以检查是否抛出了正确的异常。

我的单元测试示例:

expect(() => parser.parse(raw), throwsA(isInstanceOf<FailedCRCCheck>()));

希望这会有所帮助。

【讨论】:

以上是关于你如何在 Dart 中对异常进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

Dart 单元测试应因异常而失败

如何在单元测试中访问 Dart 类

如何在订阅Angular7单元测试用例中对代码进行单元测试

如何在 Typescript 中对私有方法进行单元测试

如何在C#中对单元测试性能优化进行单元测试?

如何在 java 中对这个方法进行单元测试?