On May 27, 1:46 pm, nil <[email protected]> wrote:
> I was looking
> athttp://saucelabs.com/blog/index.php/2009/12/running-your-selenium-tes...
> and in the comments, :Scott suggested that a macro could reduce some
> of the boilerplate that you see here:
>
> (def test-google
> {
> :name "google"
> :test (fn [client]
> (doto client
> (.open "http://www.google.com")
> (.type "q" "Sauce Labs")
> (.click "btnG")
> (.waitForPageToLoad "5000"))
> (.isTextPresent client "Selenium"))})
>
> (def test-yahoo
> {
> :name "yahoo"
> :test (fn [client]
> (doto client
> (.open "http://yahoo.com")
> (.type "p" "Sauce Labs")
> (.click "search-submit")
> (.waitForPageToLoad "5000"))
> (.isTextPresent client "Selenium"))})
>
> You can see the boilerplate of defining the map, typing the names of
> the two keys, calling the thing "test-<name>" ... So I tried writing a
> macro for this. But when I use my first attempt, it says Can't use
> qualified name as parameter. Here's my first attempt:
>
> (defmacro deftest [name & body]
> (let [test-n (symbol (str "test-" name))
> n (str name)]
> `(def ~test-n
> {:name ~n
> :test (fn [client]
> ~@body)})))
>
> The macro expansion of the following looks good, but actually running
> it yields the complaint mentioned above:
>
> (deftest google
> (doto client
> (.open "http://www.google.com")
> (.type "q" "Sauce Labs")
> (.click "btnG")
> (.waitForPageToLoad "5000"))
> (.isTextPresent client "Selenium"))
>
> My second attempt works ......
>
> (defmacro deftest [name client & body]
> (let [test-n (symbol (str "test-" name))
> n (str name)]
> `(def ~test-n
> {:name ~n
> :test (fn [~client]
> ~@body)})))
>
> ... but now the user has to mention the client twice:
>
> (deftest google client
> (doto client
> (.open "http://www.google.com")
> (.type "q" "Sauce Labs")
> (.click "btnG")
> (.waitForPageToLoad "5000"))
> (.isTextPresent client "Selenium"))
>
> How do I get around this?
I think what others are getting at is that you shouldn't have the
macro define the 'frame' of the (fn ...) form. Just pass it in whole
in your macro call like
(deftest google
(fn [client]
(doto client
(.open "http://www.google.com")
(.type "q" "Sauce Labs")
(.click "btnG")
(.waitForPageToLoad "5000"))
(.isTextPresent client "Selenium")))
It is a bit more boilerplate but you're less likely to shoot yourself
in the foot. One thing i've done in macros, (and I don't know how
advisable or "good clojure" this is), but, *if* you're sure all your
(fn...) forms you pass in will be explicit fn forms, and not just the
symbol of an existing function, you can extract the parameter name and
use it as your "name" field.
In the macro you'd do something like (-> (second body) first name),
which would return the string "client".
It's probably not the best idea since it *would* prevent you from
passing in symbols of existing functions, rather than (fn ...)
forms.
I'm not sure if you really require vars defined for each test, or if
you can just put them in a single map like so:
(def tests {:google (fn [client] ...)
:yahoo (fn [client] ...)})
and then it'd be easy to process that map:
(defn generate [m]
(zipmap (keys m) (for [[k v] m] {:name (name k) :test v})))
and finally
(run-tests (generate tests))
HTH,
Jeff
--
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