(ns my-project.tests
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
ClojureScript 现在附带了 clojure.test
的端口,即 cljs.test
。它试图保留 clojure.test
提供的大多数功能,以及针对单线程环境中异步测试的增强功能。
大多数功能是通过宏提供的,因为 cljs.test
依赖于编译器反射和静态变量来提供其大部分功能。
例如,您的测试 ns 表单可能看起来像这样
(ns my-project.tests
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
您可以使用 cljs.test/deftest
和 cljs.test/is
来编写测试,与 clojure.test
相同。
例如,这是一个只有一个断言的简单测试
(deftest test-numbers
(is (= 1 1)))
您可以使用 cljs.test/run-tests
宏来运行测试。这可以在您的 REPL 中完成,也可以在您文件末尾完成。如果您有许多测试命名空间,惯用方法是创建一个测试运行器命名空间,该命名空间导入所有测试命名空间,然后调用 run-tests
。
您可能需要在调用 run-tests
之前添加 (enable-console-print!)
您可以使用 cljs.test/use-fixtures
宏声明夹具。您可以声明 :once
夹具或 :each
夹具。:once
夹具仅在命名空间内所有测试周围运行。:each
夹具在每个测试周围运行。与 clojure.test
不同,夹具被分成两个部分::before
和 :after
。这是为了使夹具即使在异步使用时也能正常工作。
(use-fixtures :once
{:before (fn [] ...)
:after (fn [] ...)})
由于客户端代码往往是高度异步的,而 JavaScript 是单线程的,因此 cljs.test
提供异步测试支持非常重要。您可以使用 cljs.test/async
宏来创建一个异步块。如果您编写了一个异步测试,您返回的最后一个值 *必须* 是异步块。
(deftest test-async
(async done
(http/get "http://foo.com/api.edn"
(fn [res]
(is (= res :awesome))
(done)))))
done
是一个函数,您可以在准备好放弃控制并允许下一个测试运行时调用它。done
可以被命名为任何东西,但保持约定可能更有意义。所有测试代码都必须在异步块中。如果您在异步块中启动了多个异步进程,您将需要协调它们。这是一个使用 cljs.core.async
的好理由
(deftest test-async
(let [url0 "http://foo.com/api.edn"
url1 "http://bar.com/api.edn"
res0 (http/get url0)
res1 (http/get url1)]
(async done
(go
(is (= (<! res0) :awesome))
(is (= (<! res1) :cool))
(done)))))
注意:您每个 deftest
表单中不能有多个异步测试,否则只会运行第一个测试。
不好
(deftest test-async
(testing "the API is awesome" ; <-- only this test will run
(let [url "http://foo.com/api.edn"
res (http/get url)]
(async done
(go
(is (= (<! res) :awesome))
(done)))))
(testing "the API is cool"
(let [url "http://bar.com/api.edn"
res (http/get url)]
(async done
(go
(is (= (<! res1) :cool))
(done))))))
好
(deftest test-async-awesome
(testing "the API is awesome"
(let [url "http://foo.com/api.edn"
res (http/get url)]
(async done
(go
(is (= (<! res) :awesome))
(done))))))
(deftest test-async-cool
(testing "the API is cool"
(let [url "http://bar.com/api.edn"
res (http/get url)]
(async done
(go
(is (= (<! res1) :cool))
(done))))))