2024 静物 Clojure 调查中分享您的想法!

欢迎!有关本站如何运作的更多信息,请查看关于页面。

0
Spec

我有一个迷你餐厅应用程序的状态数据结构如下

    {:orders {:e4d55743-c964-48e8-9cd1-cb1cf9075617 [#:helloworld.restaurant{:name "chilly parotta", :quantity 3}  #:helloworld.restaurant{:name "masal dosa", :quantity 2}]}, :menu {:kothu-parotta #:helloworld.restaurant{:name "Kothu Parotta", :price 9.5, :quantity 50},  :butter-naan #:helloworld.restaurant{:name "Butter Naan", :price 3, :quantity 50}, :paneer-butter-masala #:helloworld.restaurant{:name "Paneer Butter Masala", :price 9.5, :quantity 50}}}

我有一个函数用于更新订单中订货项目的菜单项,从库存中减去订货数量并返回新的菜单。我想验证

  1. 订单项目中的项目应在菜单中存在
  2. 在库存中的项目数量应大于订货数量

我有以下规格(注意:目前我尚未验证第2项)。当我运行这个时,对update-menu-item-for-order-item函数的调用没有验证我的断言。我在 fdef 规格中有何错误?

(s/def ::name string?)
(s/def ::price number?)
(s/def ::quantity number?)
(s/def ::order-item (s/keys :req [::name ::quantity]))
(s/def ::order-items (s/coll-of ::order-item))
(s/def ::menu-item (s/keys :req [::name ::price ::quantity]))
(s/def ::menu-item-id keyword?)
(s/def ::menu (s/map-of ::menu-item-id ::menu-item))

(s/fdef restaurant-save-menu :args (s/cat :menu-items (s/coll-of ::menu-item)))

(s/fdef update-menu-item-for-order-item
        :args (s/and (s/cat :menu ::menu :order-item ::order-item)
                     #(contains? (:menu %) (keyword (slugify (::name (:order-item %))))))
        :ret ::menu)

(stest/instrument `update-menu-item-for-order-item)
(stest/instrument `restaurant-save-menu)

1 答案

0

最佳答案
 
最佳答案

你做了什么调用?你看到了什么结果?

by
另一种调试技术是仅仅对函数的参数规范进行测试,与函数本身独立(您可以将它分离并命名以便于操作,但也可以从函数规范中检索到它)

    (s/valid? (:args (s/get-spec `update-menu-item-for-order-item)) [a-menu a-item])
by
以下是代码。当我调用restaurant-create-order时,它调用create-order,而create-order又调用update-menu-item-for-order-item。某种原因,现在断言1(所订的项目应在菜单中存在)正常工作。之前它不起作用,我现在不确定我做了什么,但现在它恢复正常了!无论如何,谢谢。

<pre>
(def restaurant (atom {}))

(defn update-menu-item-for-order-item [menu order-item]
  (let [name (::name order-item)
        item-id (keyword (slugify (::name order-item)))
        order-quantity (::quantity order-item)]
    (update-in menu
               [item-id]
               (fn [item]
                 (if (nil? item)
                   (throw (IllegalArgumentException. (str "抱歉,我们菜单中没有 " name ")))
                   (if (< (::quantity item) order-quantity)
                     (throw (IllegalArgumentException.
                          (str "数量不足 " (::name item) ",我们短缺 "
                                  (- order-quantity (::quantity item))
                                   "。请更正订单并重新提交")))
                     (assoc item ::quantity (- (::quantity item) order-quantity))))))))

(defn create-order [orders menu order-items]
  (let [order-id (keyword (str (UUID/randomUUID)))]
    {::orders (assoc orders order-id order-items)
     ::menu   (reduce #(update-menu-item-for-order-item %1 %2) menu order-items)}))

(defn restaurant-create-order [order-items]
  (swap! restaurant #(create-order (::orders %) (::menu %) order-items)))

(restaurant-create-order [{::name "chilly parotta" ::quantity 3}
                          {::name "masal dosa" ::quantity 2}])
<pre>
我没有时间阅读所有这些代码 - 你能将它简化为对一个函数的单次调用,并传递实际数据吗?
这段代码在此刻对我本人和Prabu都有效。我怀疑是这样的REPL状态过时了。
是的,谢谢 @alexmiller。代码现在可以工作了
...