如果定义了“ test-ns-hook”,则“ lein test:only foo.bar.test / testme”不会使用函数“ testme”?

时间:2019-09-06 10:12:08

标签: unit-testing clojure leiningen

我已经定义了带有测试功能的Clojure命名空间,并希望通过lein test使用Leiningen 2.9.1运行它们。

测试功能是按层次组织的。如果我只运行lein test,将提取所有deftest,从而导致测试重复。例如:

(ns foo.bar.test
   (:require
      [clojure.test         :as t]
      [clojure.spec.alpha   :as s]
      [foo.bar.main         :as sut])) ; system under test

(t/deftest test-strip-empty
   (t/is
      (s/valid? ::sut/a-spec some-value)))

(t/deftest test-strip-several-squares
   (t/is
      (s/valid? ::sut/a-spec some-value)))

; collect subtests

(t/deftest testcollect-strip
   (test-strip-empty)
   (test-strip-several-squares))

lein test将同时运行所有三个deftest条目,从而运行test-strip-emptytest-strip-several-squares两次。

可以定义函数test-ns-hook以显式调用“测试树的顶部”。

(defn test-ns-hook []
   (testcollect-strip))

如果存在,lein test将仅呼叫test-ns-hook

哪个好!

但是一旦存在,我就不能再进行个别测试了。

lein test :only foo.bar.test/test-strip-several-squares

lein test foo.bar.test

Ran 0 tests containing 0 assertions.
0 failures, 0 errors.

不好!

删除test-ns-hook的定义,即可使用:

lein test :only foo.bar.test/test-strip-several-squares

... 

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
Tests failed.

是否可以通过结合以下两项功能来最大程度地提高幸福感:使test-ns-hook保持定义状态并能够运行单独的测试?

1 个答案:

答案 0 :(得分:1)

不要像testcollect-strip那样对测试进行分组。我将其称为反模式。

您可以使用deftest宏:https://clojuredocs.org/clojure.test/testing

在单个testing格式内将各个断言分层化。
(deftest t-math
  (testing "Arithmetic"
    (testing "with positive integers"
      (is (= 4 (+ 2 2)))
      (is (= 7 (+ 3 4))))
    (testing "with negative integers"
      (is (= -4 (+ -2 -2)))
      (is (= -1 (+ 3 -4))))))

~/expr/demo > lein clean ; lein test

lein test _bootstrap

-------------------------------
   Clojure 1.10.0    Java 12
-------------------------------

lein test tst.demo.core

Ran 2 tests containing 4 assertions.
0 failures, 0 errors.

您还可以使用 test选择器仅运行一部分测试:

~ > lein help test
Run the project's tests.

Marking deftest or ns forms with metadata allows you to pick selectors to
specify a subset of your test suite to run:

    (deftest ^:integration network-heavy-test
      (is (= [1 2 3] (:numbers (network-operation)))))

Write the selectors in project.clj:

    :test-selectors {:default (complement :integration)
                     :integration :integration}

Arguments to this task will be considered test selectors if they are keywords,
otherwise arguments must be test namespaces or files to run. With no
arguments the :default test selector is used if present, otherwise all
tests are run. Test selector arguments must come after the list of namespaces.

A default :only test-selector is available to run select tests. For example,
`lein test :only leiningen.test.test/test-default-selector` only runs the
specified test. A default :all test-selector is available to run all tests.

Arguments: ([& tests])

因此,将元数据添加到测试定义中

(deftest ^:basic-math t-math
  (testing "Arithmetic"
    (testing "with positive integers"
      (is (= 4 (+ 2 2)))
      (is (= 7 (+ 3 4))))
    (testing "with negative integers"
      (is (= -4 (+ -2 -2)))
      (is (= -1 (+ 3 -4))))))

并声明测试选择器:basics抢占:basic-math中标有project.clj的所有内容:

(defproject foo.bar "0.1.0-SNAPSHOT"
  ...
  :test-selectors {:basics :basic-math})

现在可以通过以下方式仅运行标有:basic-math的测试:

~ > lein test :basics

还有另外一个技巧要记住。测试代码(目录/文件)的名称空间结构不需要与源代码的名称空间结构匹配。您可能只有一个源代码ns super.calc,但是有一个完整的测试名称空间层次结构。我给它们都加了根tst.前缀,我认为这比在所有内容上加上_test后缀会带来更好的命名结构:

tst.super.calc
tst.super.calc.add
tst.super.calc.add.int
tst.super.calc.add.int.pos
tst.super.calc.add.int.neg
tst.super.calc.add.float
tst.super.calc.add.float.pos
tst.super.calc.add.float.neg
tst.super.calc.mult
...

因此您可以根据需要获得细粒度的图像。将此与lein测试选择器混合使用,可以实现几乎无限的细粒度控制。


也是

请签出lein-test-refresh,这是我最喜欢在lein中进行测试的方式

https://github.com/jakemcc/lein-test-refresh