Unit testing clojure:优雅地模拟具有不同值的函数
在编写单元测试时,我有时不得不模拟一个函数,以便为每个函数调用返回一系列定义的值 目前我正在做这样的事情:Unit testing clojure:优雅地模拟具有不同值的函数,unit-testing,clojure,Unit Testing,Clojure,在编写单元测试时,我有时不得不模拟一个函数,以便为每个函数调用返回一系列定义的值 目前我正在做这样的事情: (testing "fitness-proportionate selection" ; store sequence of rand values in atom, first val is ignored as we always use rest ; normalized fitness: 0: 0 1: 1/6 2: 1/3 3: 1/2 ; summed fitnes
(testing "fitness-proportionate selection"
; store sequence of rand values in atom, first val is ignored as we always use rest
; normalized fitness: 0: 0 1: 1/6 2: 1/3 3: 1/2
; summed fitness 0: 0 1: 1/6 2: 1/2 3: 1
(let [r (atom [0 1 1/2 1/6 0])] (with-redefs [rand (fn [] (first (swap! r rest)))]
(is (= [3 2 1 0] (fitness-proportionate-selection [0 1 2 3] identity))))))
有人能帮我找到一个更优雅的方法吗?
可读性更强,逻辑性更少的东西。
这将减少单元测试本身的错误。
我目前使用的是
clojure.test
,我不想使用额外的库。除了使用某种引用保存它应该返回的值序列之外,我想不出其他方法来模拟rand
函数。这是有意义的,因为rand
本身就是一个从其他(伪随机)源生成其值的函数
也就是说,我将创建一个高阶函数,该函数返回基于数字序列的数字生成器,而不是将该逻辑嵌入测试代码中
(defn gen-rand
"Returns a no args function that mocks `rand`,
which returns on each call a number from s in
the same order provided."
[s]
(let [x (atom s)]
#(let [n (first @x)]
(swap! x rest)
n)))
(defn fitness-proportionate-selection
"Mock function."
[s f]
(vec (repeatedly 4 rand)))
(testing "fitness-proportionate selection"
(with-redefs [rand (gen-rand [1 1/2 1/6 0])]
(is (= [1 1/2 1/6 0] (fitness-proportionate-selection [0 1 2 3] identity)))))
请注意,我更改了代码,以便返回提供给
gen rand
的序列中的所有值,并且不会丢弃第一个值。这是一个很好的解决方案。我认为值得指出的是,上面编写的gen rand
函数允许您模拟任何0-arity函数以按顺序返回一系列值,只需简单的调整,它就可以模拟任何arity函数。这在测试中是一个很好的助手函数。