在Racket中对许多不同的文件使用一组单元测试

时间:2013-05-15 17:31:25

标签: unit-testing racket

我正在寻找有关如何构建我的Racket程序的建议。目前,我有大约5个不同版本的程序,每个程序都有相同的单元测试(RackUnit),只是添加到每个文件的末尾。这很难维护。

我想要做的是将测试拉出到一个单独的文件中,并要求RackUnit为每个程序运行一次测试。但我不知道该怎么做。有什么建议吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

在这种情况下,也许我们可以通过使用Racket的reflection system来做一些高度动态的事情。

比如说,我们确保一组模块都提供了一个函数f,它似乎是一个单调递增的函数。我们如何编写一个使用相同电池测试来测试一组实现的框架?

我们可以编写一个:

  • 构建一个requires有问题的实施模块和
  • 的模块
  • 对它运行一组测试。

代码可能如下所示:

(define (test-module-with-monotonic-f module-path-name)
  (define ns (make-base-namespace))
  (printf "testing ~s\n" module-path-name)
  (eval `(begin (module a-test-module racket/base
                  (require rackunit
                           (file ,(path->string module-path-name)))
                  (check-true (> (f 1) (f 0))
                              (format "~a fails to provide monotonic f" ,module-path-name))
                  (check-true (> (f 3) (f 2))
                              (format "~a fails to provide monotonic f" ,module-path-name)))
                (require 'a-test-module))
        ns))

执行测试模块的构建,并使用动态eval运行它。 eval通常被认为是邪恶的,但在这种特殊情况下,我认为这是一个合适的工具。

一旦我们有了这个帮助器,我们就可以在一组文件上运行它,比如在impls子目录中:

(for ([mod-name (in-directory "impls")]
      #:when (equal? (filename-extension mod-name) #"rkt"))
  (test-module-with-monotonic-f mod-name))

您可以尝试complete running example (https://github.com/dyoo/monotonic-f-example)查看所有内容。

(顺便说一下,上面的测试显然是不够的。)

答案 1 :(得分:1)

我不知道这是多么强大,但这是一个使用卫生破坏宏的解决方案。 (Danny虽然比我聪明:)所以也许你会想听从他的意见。)

档案f1.rkt

#lang racket
(define (f x) (displayln "f1's f") (+ x 1))
(define (g x) (displayln "f1's g") (+ x 2))
(require "f-tests.rkt")
(tests)

档案f2.rkt

#lang racket
(define (f x) (displayln "f2's f") (+ 1 x))
(define (g x) (displayln "f2's g") (+ 2 x))
(require "f-tests.rkt")
(tests)

档案f-tests.rkt

#lang racket
(provide tests)
(define-syntax (tests stx)
  (syntax-case stx ()
    [(_)
     (datum->syntax 
      stx
      '(begin
         (require rackunit)
         (check-equal? (f 10) 11)
         (check-equal? (g 20) 22)))]))

datum->syntax表示tests宏应使用stx上下文中的标识符,即宏调用的位置(通常是宏)将在宏定义时使用标识符。运行文件f1.rktf2.rkt将运行测试。 (打印只是为了证明正在调用正确的函数。)