【问题标题】:Racket test for Exception异常的球拍测试
【发布时间】:2016-09-30 13:16:41
【问题描述】:

我正在使用 Racket 中的异常处理迈出第一步,并想编写一个单元测试来检查程序是否针对特定输入引发异常。

以下是我已经拥有的:

引发异常的过程:

(define (div-interval x y)
  ;; EXERCISE 2.10
  ; exception handling
  (with-handlers
    ([exn:fail:contract:divide-by-zero?
      (lambda (exn)
        (displayln (exn-message exn))
        #f)])

    (if (or
      (>= (upper-bound y) 0)
      (<= (lower-bound y) 0))

      (raise
        (make-exn:fail:contract:divide-by-zero
        "possible division by zero, interval spans zero"
        (current-continuation-marks)))

      (mul-interval
        x
        (make-interval
          (/ 1.0 (upper-bound y))
          (/ 1.0 (lower-bound y)))))))

单元测试:

(require rackunit)

(define exercise-test
  (test-suite
    "exercise test suite"

    #:before (lambda () (begin (display "before")(newline)))
    #:after (lambda () (begin (display "after")(newline)))

    (test-case
      "checking interval including zero"
      (check-exn
        exn:fail:contract:divide-by-zero?
        (div-interval
          (make-interval 1.0 2.0)
          (make-interval -3.0 2.0))
        "Exception: interval spans zero, possible division by zero")))

(run-test exercise-test)

这个测试套件中还有一些测试,但它们是针对其他程序的,所以我没有将它们包含在这段代码中。当我运行我的程序时,我得到以下输出:

before
possible division by zero, interval spans zero
after
'(#<test-success> #<test-success> #<test-success> #<test-success> #<test-error>)

&lt;test-error&gt; 用于本文中的测试用例。

该过程似乎没有引发异常。

这是因为我的过程中有一个handler,它返回#f,因此已经“吃掉”了异常?

我通常如何为引发的异常编写单元测试?

【问题讨论】:

    标签: unit-testing exception racket raise


    【解决方案1】:

    您的代码没有引发异常是绝对正确的,因为with-handler 捕获了它并返回了#f。如果您希望with-handler 为您重新引发异常,您需要使用raise,使您的代码看起来像:

    (define (div-interval x y)
      (with-handlers
        ([exn:fail:contract:divide-by-zeor?
          (lambda (e)
            <do-stuff>
            (raise e))])
        <function-body>)
    

    现在您的处理程序仍将运行,但最后它会为您重新引发异常。

    至于测试,你说check-exn 是正确的方法是绝对正确的。除了因为 check-exn 是一个过程,您需要将代码包装在一个 thunk 中,使其看起来像:

    (require rackunit)
    (check-exn
      exn:fail:contract:divide-by-zero?
      (lambda ()
        (div-interval
          (make-interval 1.0 2.0)
          (make-interval -3.0 2.0))))
    

    【讨论】:

    • 你的意思是我必须将除法函数调用包装在 lambda 表达式中,以便不立即计算除法,而是使其成为在 check-exn 内调用的函数?
    • 是的,这正是我的意思。
    • 工作正常,谢谢!我注意到在命令行上我仍然可以打印出异常的上下文。这是使用check-exn 时的正常情况,还是因为我在两者之间捕获了一次异常并重新引发它?
    • 这是因为您的异常处理程序中有(displayln (exn-message exn))。如果你把它拿出来,异常就不会再打印出来了。但是,我应该注意到,此时您只是捕获并立即重新引发异常,因此您不再需要 with-handlers
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 2014-07-07
    • 2011-01-28
    • 2012-09-27
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多