球拍异常测试
Racket test for Exception
我正在 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>)
其中 <test-error>
用于此 post 中的测试用例。
程序似乎没有引发异常。
这是因为我的程序中有一个 handler
,returns #f
因此已经 "ate" 异常?
我通常如何为引发的异常编写单元测试?
你的代码没有引发异常是完全正确的,因为 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))))
我正在 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>)
其中 <test-error>
用于此 post 中的测试用例。
程序似乎没有引发异常。
这是因为我的程序中有一个 handler
,returns #f
因此已经 "ate" 异常?
我通常如何为引发的异常编写单元测试?
你的代码没有引发异常是完全正确的,因为 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))))