在编写单元测试时,我有时需要模拟一个函数来为每个函数调用返回一系列定义的值。
目前我正在做这样的事情:
(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
,并且不希望使用其他库。
答案 0 :(得分:3)
我想不出一种模仿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
的序列中的所有值,并且不会丢弃第一个