On Dec 29, 9:12 pm, Larrytheliquid <larrytheliq...@gmail.com> wrote:
> 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.

Hi Larry,

You have laid out pretty clearly where I would like test-is to go
next.  I've been experimenting with a "context" macro and have thought
about using strings for test names.

I feel like there are two slightly different directions the library
could go right now, so I need more feedback on what is most useful to
people using it.  So, here's a dump of what's in my brain right now,
open for comment/discussion.

Originally, I assumed tests would be defined in metadata, like this:

(defn my-function ([x y]  ... do stuff ...)
  {:test (fn [] (is (= 12 (my-function 3 4)))

I felt it was beneficial to have tests and code right next to each
other, and the clojure.core/test function suggested that this would be
a good style for Clojure.

But it seems like no one except me is using test-is that way.
Instead, most people are using "deftest", which is fine, just not what
I anticipated.

In the current design of test-is, every test must be attached to
the :test metadata of a Var.  That's why "deftest" currently requires
a symbol, even a generated one -- it needs a Var to attach the
metadata to.  The "run-tests" function iterates through every Var in a
namespace, looks for a function in the :test metadata, and calls it.

I like and use RSpec, but I felt it was better suited to the Object-
Oriented style of Ruby than to the Lispy style of Clojure.  But maybe
not.


Recently, I changed "deftest" so that tests can be called like normal
functions, and nested, like this:

(deftest foo ....)
(deftest bar ...)
(deftest everything
  (foo)
  (bar))

This was inspired by Peter Seibel's example in Practical Common Lisp:
http://www.gigamonkeys.com/book/practical-building-a-unit-test-framework.html

This allows tests to be nested, but it still works within the tests-
are-Var-metadata framework.  Failure reports give the nested names,
like "Failure in (everything foo)".

Trying to add "contexts" confuses things a bit.  What is a "context",
exactly?  In RSpec, it maps conceptually to a class, with external
state handled by before/after functions.  You can do that in test-is
now:

(deftest in-context-foo
  ... setup context ...
  ... call each test function ...
  ... teardown context ...)

This way, you can re-use the same test function in multiple contexts.
In RSpec, tests are defined in a single context, so it's a little less
flexible (without the addition of share-test and use-test, as in
Specjure).

So, finally, here are the two directions I feel test-is could go next:
1. RSpec-style: Abandon the Var/metadata framework, use strings for
test names, and store tests in a global data structure.
2. Keep tests as functions, add doc strings, use nested tests for
context.

I prefer 2, because I think it's more functional and requires less
bookkeeping code.  For example, in specjure, you added share-test, use-
test, $assoc!, and $get.  The first two are unnecessary if tests are
functions, and the latter two can be handled by binding, like this:

(declare *stack*)

(deftest peek-returns-nil
  (is (nil? (peek *stack*)))

(deftest with-empty-stack
  (binding [*stack* (list)]
    (peek-returns-nil))))

Basically, I think tests are easier to write when they look more like
ordinary code.  You also get automatic bonuses, like source line
numbers, from the compiler.

One last thing: it seems to be often overlooked that the "is" macro
can take a second argument, a doc string:
(is (= 4 (+ 2 2)) "two and two make four")
That doc string will be included in failure reports.  If I add doc
strings to deftest, you've basically got all the necessary
infrastructure for RSpec-style comment strings.

signing off, for now,
-Stuart Sierra
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to