Unit testing 人们测试clojure.spec规格是否常见?
我在自学Clojure,我一直在做一个简单的玩具项目,创建一个Kakebo(日本预算工具)供我学习。首先,我将使用CLI,然后是API 由于我刚刚开始,我已经能够“摸索”规范,这似乎是clojure中用于验证的一个很好的工具。因此,我的问题是:Unit testing 人们测试clojure.spec规格是否常见?,unit-testing,clojure,clojure.spec,midje,clojure-testing,Unit Testing,Clojure,Clojure.spec,Midje,Clojure Testing,我在自学Clojure,我一直在做一个简单的玩具项目,创建一个Kakebo(日本预算工具)供我学习。首先,我将使用CLI,然后是API 由于我刚刚开始,我已经能够“摸索”规范,这似乎是clojure中用于验证的一个很好的工具。因此,我的问题是: 人们测试他们自己的书面规范 我像下面的代码一样测试了我的。关于如何让这个更好的建议 据我所知,有一些方法可以通过生成测试自动测试函数,但是对于基本规范来说,这种测试是一种好的实践吗 规格文件: (ns kakebo.specs (:要求[clojure.
(ns kakebo.specs
(:要求[clojure.spec.alpha:as s]))
(s/def::条目类型#{:收入:支出})
(s/def::费用类型#{:固定:基本:休闲:文化:额外费用})
(s/def::收入类型{:薪金:投资:偿还})
(s/def::类别类型(s/or::费用类型::收入类型))
(s/def::money(s/and double?#(>%0.0)))
(s/def::date(java.util.date.))
(s/def::项目字符串?)
(s/def::供应商(s/nilable字符串?)
(s/def::entry(s/keys:req[::entry type::date::item::category type::vendor::money]))
测试文件:
(ns kakebo.specs-test
(:require[midje.sweet:参考:全部]
[clojure.spec.alpha:as s]
[kakebo.specs:参考:全部])
(事实“金钱”
(事实“大于零”
(s/valid?:kakebo.specs/money 100.0)=>true
(s/valid?:kakebo.specs/money-10.0)=>false)
(事实“必须是双重的”
(s/valid?:kakebo.specs/money“foo”)=>false
(s/valid?:kakebo.specs/money 1)=>false)
(事实“条目类型”
(事实“有效类型”
(s/valid?:kakebo.specs/entry-type:income)=>true
(s/valid?:kakebo.specs/entry-type:expense)=>true
(s/valid?:kakebo.specs/entry-type:fixed)=>false)
(事实“费用类型”
(事实“有效类型”
(s/valid?:kakebo.specs/expense-type:fixed)=>true)
最后一个问题是,如果我尝试以下导入,为什么我无法访问规范:
(ns规格测试)
(:要求[kakebo.specs:as ks]))
(事实“我的事实”(s/valid?:ks/money 100.0)=>真)
无论我是否使用spec,我个人都不会编写与代码紧密耦合的测试。这几乎是对每一行代码的测试——这可能很难维护
规范中有几个看起来是错误的:
;;这将不起作用,您可能想说的是类别类型
;; 是支出类型和收入类型的结合
(s/def::类别类型(s/or::费用类型::收入类型))
;; 这将不起作用,您可能想检查该值是否正确
;; 是Date类的实例
(s/def::date(java.util.date.))
通过将现有的原子规范组合成更高级别的规范,在应用程序中完成繁重的工作,您确实可以获得很多超出规范的内容。我会测试这些更高级别的规范,但通常它们可能在常规函数后面,并且这些规范可能根本不会公开
例如,您已将条目
定义为其他规范的组合:
(s/def::entry(s/keys:req[::entry type::date::item::category type::vendor::money]))
这用于验证所有必需的数据是否存在,以及生成使用此数据的测试,但数据中存在一些可传递的依赖项,例如:expense
不能是:salary
类型,因此我们可以将其添加到条目
规范中:
;;反编译条目类型
(定义收入分录?#{:收入})
(定义费用输入?#{:费用})
(s/def::条目类型(clojure.set/union expense entry?income entry?)
;; 反编译类别类型
(def费用类型?#{:固定:基本:休闲:文化:额外费用})
(定义收入类型?#{:工资:投资:报销})
(s/def::类别类型(clojure.set/union费用类型?收入类型?)
(s/def::money(s/and double?#(>%0.0)))
(s/def::date(部分实例?java.util.date))
(s/def::项目字符串?)
(s/def::供应商(s/nilable字符串?)
(s/def::费用
(s/cat::分录类型费用分录?
::类别类型(费用类型?)
(s/def::收入
(s/cat::分录类型收入分录?
::类别类型(收入类型?)
(定义费用或收入?[m]
(let[数据(映射m[::条目类型::类别类型])
(或有效::费用数据)
(s/有效::收入数据)
(s/def::进入
(s/和
费用还是收入?
(s/keys:req[::条目类型::日期::项目
::类别类型::供应商::货币]))
根据应用程序甚至上下文的不同,您可能有不同的规格来描述相同的数据。上面我将费用
和收入
合并到条目
中,这可能有助于输出到报告或电子表格,但在应用程序的另一个区域,为了数据验证目的,您可能希望将它们完全分开;这正是我使用规范最多的地方——在系统的边界,例如用户输入、数据库调用等
我对规范的大多数测试都是在验证进入应用程序的数据方面。我测试单个规范的唯一时间是它们是否包含业务逻辑,而不仅仅是数据类型信息。
::ks/money
应该可以工作(注意,前面两个:
@cfrick是这样的,因为来自另一个名称空间的符号现在是“混合的”使用当前名称空间,因此我可以使用两个:
?这些文档是用于cljs的,但是它们解释得很好:谢谢你的回答!我想现在这更清楚了。