7

Let's say I have some file a.rkt:

#lang racket
(define a 12)

I now want to write some test cases, using the file b.rkt that requires a.rkt:

#lang racket
(require "a.rkt")
a

Is there any way I can get b.rkt to recognize the identifier defined in a.rkt without having to provide it from the first file? (Ideally without having to change the first file at all.)

I don't see anything immediately in the documentation for require/provide.

Leif Andersen
  • 21,580
  • 20
  • 67
  • 100

2 Answers2

6

As Leif mentions, RackUnit's require/expose will allow using unprovided identifiers in other modules, but its own documentation doesn't promise a very strong guarantee:

Note that require/expose can be a bit fragile, especially when mixed with compiled code. Use at your own risk!

Another approach would be to use submodules, which can effectively provide a sanctioned way to export a private API for use in tests or other means.

For example, consider a module that implements a function to test if a string contains a single word:

#lang racket

(provide word?)

(define (word? str)
  (not (ormap space? (string->list str))))

(define (space? c)
  (eq? c #\space))

(This is, perhaps, not the most realistic example, but bear with me.)

It might be useful to test the space? function to ensure it works, but it likely shouldn't be part of the public API. To create an "escape hatch", it's possible to define a submodule that exports this binding:

(module+ for-testing
  (provide space?))

The name for-testing is arbitrary—it could be anything. Either way, it is now possible to require that submodule in another module to get access to the private bindings:

#lang racket

(require rackunit
         (submod "a.rkt" for-testing))

(check-true (space? #\space))
(check-false (space? #\a))

This is something of a safer way to expose identifiers from modules without exposing them to all consumers.

Alexis King
  • 43,109
  • 15
  • 131
  • 205
  • Sometimes, it's unfeasible to change the original source to add extra `provide`s, e.g., students who do not follow directions. Dan Feltey's testing framework uses `require/expose` (and friends) in this manner: https://github.com/dfeltey/pdptest. (Not contradicting your answer, just describing another use case context.) – stchang Dec 07 '15 at 14:57
5

You can use require/expose in b.rkt to get access to the binding in a.rkt. b.rkt would look something like this:

#lang racket
(require rackunit)
(require/expose "a.rkt" (a))
a
Leif Andersen
  • 21,580
  • 20
  • 67
  • 100