Hello Alexander, Marc, Ah, now I get this. Thank you for your responses!
вторник, 21 июля 2015 г., 17:54:42 UTC+3 пользователь Yuri Govorushchenko написал: > > 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.