使用Clojure + Midje重新定义宏操作

时间:2012-04-30 21:44:29

标签: macros clojure midje

背景

我是Clojure的新手所以请原谅任何明显的错误。我正在尝试测试一些使用redis-clojure库的Clojure数据访问代码。当然,我的集成测试将测试整个堆栈,但我不希望我的单元测试依赖于连接到redis服务器实例。使用Midje模拟实际的Redis命令似乎相对简单,但连接宏更难以处理。

需要建议

通过Midje文档似乎无法做或找不到的方法是模拟redis连接或重新定义宏。 core.clj 中相关的顶级连接宏是:

(defmacro with-server
  "Evaluates body in the context of a connection to Redis server
  specified by server-spec.

  server-spec is a map with any of the following keys:
    :host     (\"127.0.0.1\")
    :port     (6379)
    :db       (0)
    :timeout  (5000)
    :password (nil)"
  ([server-spec & body]
     `(with-connection connection# *pool* ~server-spec
        (binding [redis.vars/*channel* (make-direct-channel connection#)]
          ~@body))))

original code in context here

我似乎无法在我的测试代码中重新定义宏,并且在函数中包装宏不会让我任何进一步的前进,因为我仍然需要执行主体来产生我的结果。我理想的做法是执行传递给连接宏的主体并丢弃宏的其余部分。有任何想法吗?

2 个答案:

答案 0 :(得分:2)

我经常编写绑定包装器宏进行测试。这些宏只是将其他东西绑定到无法测试的函数或宏。在这种情况下,我会沿着这些行写一些东西

(defmacro my-fake-with-server []
   ....)

(defmacro with-fake-with-server
      (binding [redis.core/with-server my-fake-with-server]
               (insert test here)))

(deftest my-test (with-fake-with-server (function-that-uses-with-server)))

这样可以保留测试代码中的所有模拟内容。

答案 1 :(得分:1)

我建议在Midje mailing list上提出你的问题(然后,当然,在这里发布最终答案)。如果不知道你要测试什么,就很难提供建议。也许(跟随Freeman和Pryce的 Growing Object-Oriented Software (它确实适用于Clojure - 事实上,支持这种风格是我写Midje的原因)),你想把你的问题分成两部分。首先,您要构建一组隔离Redis的函数。您可以使用与真实数据库一起使用的缓慢而繁琐的直接测试来测试这些函数是否正常工作。

这些函数会隐藏连接并需要包装宏。

然后,您可以使用Midje先决条件测试您的代码是否正确调用了隔离函数。

Avdi Grimm的 Objects on Rails 是另一本关于隔离数据库的书。

注意:我对Redis一无所知,但其他几个Clojure->数据库库省去了具有智力吸引力的包装宏(with-server)。相反,它们进入有状态路由并拥有一个保存连接的全局变量,就像(例如)Ruby数据库库ActiveRecord(隐式)和Sequel(显式)那样。尽管不那么纯净,但它似乎使生活(包括测试)更简单。在Midje,这种联系可以由一位主持人代表。