【问题标题】:How do you unittest exceptions in Dart?你如何在 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
}

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

【问题讨论】:

    标签: dart


    【解决方案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>()));
        

        希望这会有所帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-10-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-06
          • 2010-09-07
          • 2017-06-10
          • 2018-10-09
          相关资源
          最近更新 更多