;; Note: originally I was just going to write Stuart, but I think input from anybody on the list could be valuable, so I'm CC'ing Clojure
Hi Stuart, I've been working on an RSpec-like library for Clojure called Specjure. It has gone through many iterations and the one that is currently up on github is not something I am satisfied with. As I get closer to something I like, it seems that what I will end up with will end up with will look look like where test-is seems to be heading. So, rather than creating duplicate work I'd like to get your opinion on what I have in mind. If you like it, I'd be glad to contribute to test-is rather than creating a duplicate library. This is what I'm thinking, let me explain: http://gist.github.com/41468 (If you are familiar with RSpec, here is the equivalent RSpec example http://rspec.info/examples.html) First off, I renamed deftest to test (note this is a small design choice that I think is a good idea, but wouldn't care too much about.) I tend to write a lot of tests, and having the main keywords for tests be something short is a nice way to encourage writing many tests. The "is" macro in test-is follows this "short name for frequently used form" theme (as does def instead of define, and defn instead of define-function in clojure), and I think it's appropriate to do the same for deftest->test. Another change is that the "test" macro can take a symbol, a string, or both as arguments. This allows for more specification/RSpec/BDD-like tests to be created (I noticed you're experimenting with something similar in clojure-contrib tests, in the form of test-that). Also, if somebody wanted to just do non-specification style tests by using symbols then they are free to do so. There is also a new "context". This should be familiar to you if you've ever used RSpec or other BDD libs. It allows for arbitrary nesting of contexts. Inside of a context, you can use "test". Any test forms used in a context will inherit its description, prepending it to its own description. Quick aside: If you use a symbol, it's resolved name will be used in the description, ie: ;; the description string here would be "my-ns/my-fn run concurrently returns foo" (ns my-ns) (context my-fn "run concurrently" (test "returns foo" (is (= "foo" (my -fn :concurrent))))) You can also use the "before" and "after" forms. Any code in these will be captured into functions, and run before running any "test"s defined in the context. This is useful for things like database fixtures that must clean and repopulate database tables before running tests. The before/after forms are also inherited when nesting contexts. Another two forms are $get and $assoc! $assoc! lets you set key/value pairs to a map that is created for each test, and $get lets you access the map. This is useful for things like setting up values in a before form, and accessing them for testing and cleanup purposes in "test" and "after", respectively, ie: (context create-user "with valid attributes" (before ($assoc! :user (create-user)) (after (clean-database!)) ... other tests ... (test "is valid" (is (valid? ($get :user))))) Somtimes you write small functions that only do one thing in one context. These functions do not really need a a context form. Since "test" can take a symbol and a string optionally, it can accomodate for such cases. If there are different contexts, but no heavy set up is necessary (something you'd put in "before"), you may also want to avoid the nesting. For example, you might want to write a test like this:( (ns clojure.core) (test + "without arguments returns 0" (is (= 0 (+)))) (test + "with a single argument returns the argument" (is (= 3 (+ 3)))) (test + "with multiple arguments returns their sum" (is (= 7 (+ 4 2 1)))) However, you could also avoid some repetition if you like by using context: (context + (test "without arguments returns 0" (is (= 0 (+)))) (test "with a single argument returns the argument" (is (= 3 (+ 3)))) (test "with multiple arguments returns their sum" (is (= 7 (+ 4 2 1))))) The last things in gist I posted are share-test and use-test. This is basically just for storing functions with (share-test "my string" [arg] ... stuff ...) and calling them with (use-test "my string" :some-arg). Because context, test, before, and after are anamorphic, you could put a "before" form in their and just share that (without putting it in a "context" first.) This lets you achieve similar functionality to what is referred to as "mixins" in some languages such as Ruby. Whew, lots of stuff there. I've been going through lots of variations of how I think this kind of context-based testing would work best while retaining the simplicity and flexibility of just using "deftest/test" and this is where I'm at so far. Let me know what you think. I've basically written the above example in specjure before, so porting it to test-is wouldn't be a problem. Cheers, and thanks for the read! P.S. I just typed this stuff without a text editor so forgive any unmatched parens, etc -- Respectfully, Larry Diehl www.larrytheliquid.com --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---