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.

Reply via email to