Thank you for a reply, I totally agree with you on dependency injection. Though I'm exercising in writing a mocking framework and thought it would be an interesting feature to implement a thread-safe mocking of an implicit dependency.
среда, 22 июля 2015 г., 5:03:36 UTC+3 пользователь Surgo написал: > > Not that it's the answer you're looking for, but usually this is when you > rewrite the code you're testing to use dependency injection (ie, take the > var of interest as an argument instead of a global or in its lexical > environment). > > -- Morgon > > On Tuesday, July 21, 2015 at 10:54:42 AM UTC-4, Yuri Govorushchenko wrote: >> >> The problem I'm trying to solve is how to stub a variable (e.g. a >> function from a third-party lib) in tests so that the stubbing occurs only >> in the current thread with other threads continuing using var's root value. >> It's important because unit tests may be run in parallel. Without >> thread-local binding two threads stubbing the same function will lead to >> race conditions: >> >> (binding [somelib/foo foo-stub] ; throws java.lang.IllegalStateException: >> Can't dynamically bind non-dynamic var >> ; invoke tested code which depends on foo >> ; assert stuff >> ) >> >> I've tried to use *.setDynamic* (as described in blog post [1]) but it >> doesn't work without direct *deref*-ing of the var: >> >> (def static-var 123) >> (defn quz[] >> (.setDynamic #'static-var true) >> (binding [static-var 1000] >> (println "static-var =" static-var "deref =" @#'static-var))) >> >> (quz) ; => static-var = 123 deref = 1000 >> >> This approach seems to be used in a recent *bolth* lib [2]. And The >> strange thing is that in REPL running this code line by line works: >> >> user=> (def static-var 123) >>> #'user/static-var >>> user=> (.setDynamic #'static-var true) >>> #'user/static-var >>> user=> (binding [static-var 1000] (println "static-var =" static-var)) >>> static-var = 1000 >> >> >> Looking at Var class implementation I couldn't figure out why . >> *setDynamic* call wouldn't work. My guess is that compiler somehow >> caches initial static Var value for performance reasons?.. >> >> So the questions are: >> 1) Is it a bug that *.setDynamic* + *binding* don't work? >> 2) Is there any other way to temporally rebind static variable >> thread-locally? Considering I can't add *^:dynamic* into third-party lib >> and don't want to write a wrapper or use dependency injection in order to >> explicitly substitute the dependency in my unit tests. >> 3) Is there a Clojure parallel test runner which runs tests in new >> processes instead of threads? This would eliminate any race conditions. >> Python's *nose* test runner works this way [3]. >> 4) Maybe crazy: does Clojure allow dynamically rebinding the symbol to a >> new Var instance so that I could set *'static-var* to point at *(.setDynamic >> (Var/create)*? >> 5) Even crazier idea: can I change the nature of the var so that it >> behaves like an InheritedThreadLocal instead of ThreadLocal, but without >> forcing a user to *deref* it (as it was described in [4])? >> >> Links: >> [1] >> http://blog.zolotko.me/2012/06/making-variable-dynamic-in-clojure.html >> [2] >> https://github.com/yeller/bolth/blob/323532683e3f66ae11566db5423c1e927e51818e/src/bolth/runner.clj#L99 >> [3] >> http://nose.readthedocs.org/en/latest/doc_tests/test_multiprocess/multiprocess.html >> [4] https://aphyr.com/posts/240-configuration-and-scope - see >> "Thread-inheritable dynamic vars in Clojure" >> >> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.