Bri*_*ick 17
我没有使用speclj,我是Midje的第一作者.其他人没有提到的一点是,Midje试图利用功能语言和面向对象语言之间的差异.
一个区别是不变性.因为大多数函数仅依赖于它们的输入,而不依赖于包含的状态,所以你对它们所做的真实陈述与它们面向对象的对应物的感觉不同.在OO测试中,您可以创建表单示例:"给定此历史记录和这些输入,此方法会产生这样的结果."
似乎函数式语言中的例子只是更简单的例子:"给定这些输入,这个函数会返回这样的东西".但我不认为这是对的.我认为系统中的其他功能起着类似于状态/历史的作用:它们是你试图获得智力控制的东西之一.函数及其关系是您希望测试帮助您清楚思考的事情.
出于这个原因,Midje是在一个甜蜜的开发过程涉及说:
然后,在典型的嘲讽风格中,你会大致自上而下或从外到内发展,允许在你从错误中恢复或有更好的想法时进行不可避免的迭代.
最终的结果是成为一大堆功能,它们的相互关系由测试记录,或者(如Midje所称)是关于功能和它们所依赖的功能的"事实".不同的人评论说,Midje有一个Prolog /逻辑编程的感觉,这不是一个意外.和往常一样,测试就是例子,但是Midje试图让它们更像真实的陈述.这是其唯一真正的创新功能,即metaconstants的理由.这是他们的一个例子:
(fact "right changes the direction, but not the position"
(right (snapshot north ...position...)) => (snapshot west ...position...)
(right (snapshot east ...position...)) => (snapshot north ...position...)
(right (snapshot south ...position...)) => (snapshot east ...position...)
(right (snapshot west ...position...)) => (snapshot south ...position...))
Run Code Online (Sandbox Code Playgroud)
在这种情况下,实际位置与函数的真实性无关right,除了它永远不会改变.一个metaconstant的想法是,除了在测试中明确说明的内容之外,它是一个值,除此之外什么都不知道.经常在测试中,很难说出什么是必要的,什么是偶然的.这有很多不好的影响:理解,可维护性等.主要信息提供清晰度.如果值是包含3key 值的map或记录很重要:a,那么请明确说明:
(fact
(full-name ..person..) => "Brian Marick"
(provided
..person.. =contains=> {:given-name "Brian", :family-name "Marick"}))
Run Code Online (Sandbox Code Playgroud)
这个测试是明确约约的人什么事情---也明确什么并不重要(什么,但两个人的名字).
在数学术语中,Midje试图让你做出像"for all x where x ..."这样的陈述,同时仍然是一个测试工具,而不是一个定理证明者.
这种方法的灵感来自于" 成长面向对象软件"中描述的"伦敦风格"模拟繁重的TDD ,这种方法通常用于编写Ruby代码.但事实证明,这种感觉有着截然不同的感觉.但这种感觉需要更多的工具支持而不仅仅是with-redefs.
结果是,Midje试图找到一种功能性TDD,而不仅仅是OO TDD的一个端口.它也试图成为一种通用工具,但它是半固定的软件.正如亚伯拉罕·林肯所说:"那些喜欢这类事情的人会发现这是他们喜欢的事情."
使用Midje的最大好处是它可以提供有针对性的抽象测试,而无需测试所有零件,这些零件往往会拖累整个世界.
如果你有一个函数涉及调用辅助函数来生成时间戳,将某些东西放在数据库或消息队列中,发出API请求,缓存某些东西,记录某些东西等,你想知道发生了这些涉及世界的函数调用(有时它们发生了多少次,但是实际执行它们与你正在测试的函数无关,被调用的函数通常应该进行自己的单元测试.
假设你的代码中有这个:
(defn timestamp [] (System/currentTimeMillis))
(defn important-message [x y] (log/warnf "Really important message about %s." x))
(defn contrived [x & y]
(important-message x y)
{:x x :timestamp (timestamp)})
Run Code Online (Sandbox Code Playgroud)
以下是如何用midje测试它的方法:
(ns foo.core-test
(:require [midje.sweet :refer :all]
[foo.core :as base]))
(fact
(base/contrived 100) => {:x 100 :timestamp 1350526304739}
(provided (base/timestamp) => 1350526304739
(base/important-message 100 irrelevant) => anything :times 1))
Run Code Online (Sandbox Code Playgroud)
这个例子只是您可以快速了解您可以使用midje做什么,但展示了它擅长的本质.在这里,您可以看到表达需要的外部复杂性非常少:
我试图用这个例子做的主要观点是,它是一种非常干净和紧凑的方式来表达复杂代码的测试(并且复杂的意思是它具有可以分离的嵌入部分),而不是试图测试一切一次全部.一次测试所有内容都有其地位,即集成测试.
我被认为是有偏见的,因为我积极地使用midje,而我只看了speclj,但我的感觉是speclj可能对那些使用类似的Ruby库并且发现这种思考测试理想的方式最有吸引力,基于此经验.这是选择测试框架的一个完全可靠的理由,并且可能还有其他很好的事情,希望其他人可以评论.
我肯定会和Speclj一起去.
Speclj易于集成和使用.它的语法不像Midje那样华丽.Speclj基于RSpec,为您提供Ruby程序员习惯的所有配置,同时不会丢失Clojure的特性.
Speclj的赛车运动员很棒.
lein spec -a
Run Code Online (Sandbox Code Playgroud)
一旦你使用了一段时间,你会想知道当你不得不手动运行测试时你是如何完成工作的.
模拟是一个非问题,因为你可以简单地使用with-redefs.@ rplevy在Speclj中的例子看起来像这样.
(ns foo.core-spec
(:require [speclj.core :refer :all ]
[foo.core :as base]))
(describe "Core"
(it "contrives 100"
(let [message-params (atom nil)]
(with-redefs [base/timestamp (fn [] 1350526304739)
base/important-message #(reset! message-params [%1 %2])]
(should= {:x 100 :timestamp 1350526304739} (base/contrived 100))
(should= 100 (first @message-params))))))
Run Code Online (Sandbox Code Playgroud)
这种愚蠢的嘲弄方法是至关重要的; 没有误导.
至于测试网络应用程序,Speclj工作正常.事实上,Speclj支持是构建到Joodo中的.
免责声明:我写过Speclj
我建议使用 Midje 而不是 Speclj
对于 speclj,我不认为它对模拟有很好的支持,与 Midje 相比,文档看起来也很稀疏。
Midje 的语法也更好:
(foo :bar) => :result compared to (should= (foo :bar) :result)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3327 次 |
| 最近记录: |