racket-mock icon indicating copy to clipboard operation
racket-mock copied to clipboard

"Nested use of with-mocks not allowed" - why?

Open artemiswkearney opened this issue 4 years ago • 2 comments

I'm currently writing tests for a file that has a bunch of functions modifying shared state and, based on that state, performing I/O, sometimes using callbacks/thunks created in other functions. I want to write my tests in a way that mocks all the I/O operations, but none of the state management; however, if I'm in a with-mocks block that binds the mock I want to check (one used in a callback), I can't also be in one for the function that triggers the callback after some I/O. (simplified use case:

#lang racket

(module+ test
  (require mock/rackunit))

(require mock)

(struct event (time proc))

(define events '())

(define/mock (schedule-reminder! time message)
  #:mock displayln #:as print-with #:with-behavior void
  (set! events (cons (event time (thunk (displayln message))) events)))

(define/mock (check-events!)
  #:mock current-seconds #:as get-time-with #:with-behavior (const 0)
  (define time (current-seconds))
  (for ([e events])
    (when
      (> time (event-time e))
      ((event-proc e))))
  (set! events (filter (λ (e) (< time (event-time e))) events)))

(module+ test
  (with-mocks schedule-reminder!
    (schedule-reminder! 60 "Hello!")
    #;; disallowed
    (with-mocks check-events!
      (check-events!)
      (check-mock-num-calls print-with 0)
      (with-mock-behavior ([get-time-with (const 100)])
        (check-events!)
        (check-mock-calls print-with
                          (list (arguments "Hello!"))))))
  (with-mocks check-events!
      (check-events!)
      #;; print-with isn't bound here
      (check-mock-num-calls print-with 0)
      (with-mock-behavior ([get-time-with (const 100)])
        (check-events!)
        #;; or here
        (check-mock-calls print-with
                          (list (arguments "Hello!"))))))

)

artemiswkearney avatar Dec 11 '21 01:12 artemiswkearney

It seems like just removing the check for nested with-mocks gets this specific example working. However, I assume the check is there for some reason, so I won't PR yet.

artemiswkearney avatar Dec 11 '21 02:12 artemiswkearney

It's been several years so my memory is hazy, but I think the check was there because it was a low-effort way to prevent (with-mocks foo (with-mocks foo _)) from happening.

I don't personally use mocks anymore, actually. I prefer making fakes instead, by which I mean simplified IO-free and low-dependency implementations of stateful interfaces.

jackfirth avatar Dec 14 '21 21:12 jackfirth