Hi, Shantanu.

Thanks for the suggestions.  A couple thoughts:

1. Many times, I seem to stub or mock things that are scattered here and 
there in the code, like things that send email or log metrics, etc.  so 
they are not really isolated (or isolatable??), but I still want to test 
that they get called.
2. So I'm usually mocking utility functions that have side effects.  Am I 
mocking at the right level?
3. For these types of things, even if I make protocols for them, passing 
them all in as arguments seems like it could get messy fast.  E.g. my 
function used to be (f x), but now it's (f x logger emailer metric-logger 
...)
4. I'm not really familiar with the methods you describe, so any 
elaboration on your comments would be welcome.  Or even better, a link to a 
project that uses the designs you mentioned.

Thanks,
Leif

On Monday, March 25, 2013 5:57:34 AM UTC-4, Shantanu Kumar wrote:
>
>
>
> On Monday, 25 March 2013 06:45:32 UTC+5:30, Leif wrote:
>>
>> Hello, fellow Clojurians.
>>
>> One problem I've run into when stubbing fns is that with-redefs doesn't 
>> play well with concurrency.  E.g. 
>> http://clojuredocs.org/clojure_core/clojure.core/with-redefs#example_994  
>> The problem arises because, quoting with-redef's docstring, "These 
>> temporary changes will be visible in all threads."
>>
>> Let's say you're stubbing the fn 'f' with the fn 'stub'.  Here is an 
>> irritating sequence of events:
>> 1:  test1 redefs f to stub, saving the initial fn
>> 2:  test2 redefs f to stub, saving **the current value of f, which is 
>> stub**
>> 3:  test1 completes, resetting f to its initial fn
>> 4:  test2 completes, **resetting f to the stub fn**
>> 5:  test3 starts, expecting the fn f to work normally, and fails
>>
>> We actually ran into the problem because there was a delay in our app's 
>> init fn, and so the first one of our integration tests that ran permanently 
>> rewrote some fns.  I would imagine that this could even happen in unit 
>> tests, though, if your test runner executed tests in parallel.
>>
>> Has anyone run into a similar problem, and come up with a safer way of 
>> stubbing / mocking non-dynamic vars?
>>
>
> If you could design the code around Primatic's Graph: 
> https://github.com/Prismatic/plumbing it may be cleaner and easier to 
> isolate the dependencies, hence making them easy to mock.
>
> Another (lengthier) approach would be to model anything mockable as a 
> protocol, and pass the implementation as function argument. As a bonus, 
> this lets one keep the code mostly unaware of impurity. For production and 
> integration-tests initialize the application at its entry point and 
> instantiate the chain of dependencies, then pass the top level dependencies 
> as function arguments. For unit tests where you need a mock dependency, 
> simply pass a mock implementation of the protocol as a function argument. 
> In cases where the application has several reference types for complex 
> state management, an inside-out design will probably help a lot together 
> with this approach for testing.
>
> Shantanu
>

-- 
-- 
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/groups/opt_out.


Reply via email to