Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent and confusing behavior with with-redefs #126

Open
eigenhombre opened this issue Mar 17, 2015 · 10 comments
Open

Inconsistent and confusing behavior with with-redefs #126

eigenhombre opened this issue Mar 17, 2015 · 10 comments

Comments

@eigenhombre
Copy link

lein spec and lein spec -a treat the following differently; the test fails in the former, and passes in the latter.

(ns myapp.test
  (:require [speclj.core :refer :all]))

(def db "database-a")

(with-redefs [db "database-b"]
  (describe "db"
    (it "should be called database-b"
      (should= db "database-b"))))

In general, we find that running lein spec requires with-redefs to be specified within it blocks (and lein spec -a doesn't), making it harder to mock out e.g. a database connection for a whole set of tests. Can this be improved somehow?

@trptcolin
Copy link
Collaborator

Usually I've used around for this, something like

(ns myapp.test
  (:require [speclj.core :refer :all]))

(def db "database-a")

(describe "db"
  (around [it] (with-redefs [db "database-b"] (it)))

  (it "should be called database-b"
    (should= db "database-b")))

Not sure why the difference between lein spec -a and lein spec, or if this gets rid of the problem completely, but that's at least a workaround in case you're not familiar with around.

@thesoftwarephilosopher
Copy link
Contributor

I wonder if this could have to do with Speclj internally requiring a different version of Clojure when run with the vigilant runner than with the standard, so that, when lein spec is run, certain forms do nothing when rebound with with-redefs and require binding instead.

@eigenhombre
Copy link
Author

@trptcolin thanks for the suggestion. That works; however, the following does not:

(ns myapp.test
  (:require [myapp.test :refer :all]
            [speclj.core :refer :all]))

(def db "database-a")

(defmacro describe-with-db [text & body]
  `(describe ~text
     (around [it] (with-redefs [db "database-b"] (it)))
     ~@body))

(describe-with-db "db"
  (it "should be called database-b"
    (should= db "database-b")))

Throws

1) java.lang.RuntimeException: Can't use qualified name as parameter: speclj.core/it, compiling:(myapp/test.clj:20:1) [...]

-- this more closely matches what we want to do (dry out DB mocking to use an in-memory test DB rather than a "real" one).

Any suggestions (I know you know one or two things about macros AND speclj :-) )? Thanks in advance!

@thesoftwarephilosopher
Copy link
Contributor

@eigenhombre I believe this is solved by changing db in your with-redefs with #'db (which is short-hand for (var-get db)).

@eigenhombre
Copy link
Author

@sdegutis It's complaining about it, not db ... it looks like one of the macros is expanding into (let [it ...] ...) which wants a gensym inside the (remaining) macro.

@trptcolin
Copy link
Collaborator

@eigenhombre Yep! it -> it# (auto-gensym), as below:

(ns myapp.test
  (:require [myapp.test :refer :all]
            [speclj.core :refer :all]))

(def db "database-a")

(defmacro describe-with-db [text & body]
  `(describe ~text
     (around [it#] (with-redefs [db "database-b"] (it#)))
     ~@body))

(describe-with-db "db"
  (it "should be called database-b"
    (should= db "database-b")))

Does that do the trick for you?

@eigenhombre
Copy link
Author

@trptcolin works for our minimal test case -- trying it in our app. I also called it foo# instead of it# and that also worked. So I guess the name is just a temporarily alias for all the forms in the body?

@trptcolin
Copy link
Collaborator

Yep, inside around, it (or whatever you name it) is just a function that represents all the tests to be executed inside that describe/context.

@eigenhombre
Copy link
Author

@trptcolin We're unblocked -- that worked for us. I guess there's still the open question of why this is only needed with lein spec and not lein spec -a -- anyways, thanks for the help!

@TheTedHogan
Copy link

I'm running into the same issue. It seems to be a difference between the standard runner and the vigilant runner.
Using around works, but I'm also curious why the runners are treating with-redefs differently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants