1

在编写单元测试时,我有时必须模拟一个函数来为每个函数调用返回一系列定义的值。

目前我正在做这样的事情:

(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并且不希望使用其他库。

4

1 回答 1

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值,并且不丢弃第一个值。

于 2013-06-10T19:26:04.533 回答