On Fri, Sep 16, 2011 at 4:01 PM, Stuart Sierra <[email protected]>wrote:
> On Friday, September 16, 2011 3:12:49 PM UTC-4, Brian Hurt wrote: >> >> How *should* I structure this code for testing? I was assuming the >> natural way to do this is to make A, B, and C separate name spaces but maybe >> this is wrong. > > > The best way to make these namespaces testable, in my opinion, is remove > the dependencies. In the ideal scenario, only the bottom layer -- layer C in > your diagram -- would have any side-effects. Layer B -- the middle layer -- > would consist entirely of pure functions that operate on the data structures > generated and consumed by C, but would have no direct dependencies on C. > Finally, layer A would tie the two together. I wrote about this approach > here: http://stuartsierra.com/2011/08/08/clojure-namespaces > > In this style, layer B is easy to unit-test. Tests for layer C are > "integration" tests that know about external services like databases. Tests > for layer A are whole-application tests. > > In my case, pretty much all the functions are of the form "do some action", and each layer is collecting simple(r) actions up into more complicated applications. The bottom level of actions may be "read an individual email" and "put an email in the database". The next level up action is "read an email and put it in the database". The next level up would be "read all the emails from this folder into the database", then "for all folders for this user", then "for all users", and so on. So this structure isn't really applicable. The reality is, of course, always more complicated. :-} > Another option is to design the APIs of B and C around an object that > represents the runtime environment. The testing environment returns mock > data; the production environment uses the real functions. This object could > be an argument to functions in B and C, or it could be a Var bound to a > special value for testing. > > We just had a long discussion on this. The problem here is fan-out. So, I'm testing function a1 in ns a. Function a1 calls function b1, b2, and b3 in ns b. b1 calls c1, c2, and c3, etc. So now, testing a single function up in ns a requires me to mock out 9 functions down in c- 27 down in ns d. Even worse, *which* functions I need to mock out, to test a, requires a knowledge of the implementations not only of a1, but also b1-b3 and possible c1-c9. And If I modify c7 or b2, I now have to remember to go fix the tests for a1 as well. This is why I'm so insistent that I can mock out b. If I can do that, then I only need to supply three functions, and which three functions require only knowledge of the specific function I'm testing. Brian -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/clojure?hl=en
