testing-clojure-cljs
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSkill: Testing Clojure ClojureScript
技能:为Clojure和ClojureScript编写测试
Goal
目标
Set up and write tests for Clojure and ClojureScript projects using cljs.test, cljs-init-tests, and shadow-cljs workflow.
使用cljs.test、cljs-init-tests和shadow-cljs工作流为Clojure及ClojureScript项目搭建并编写测试。
Use This Skill When
适用场景
- Testing Clojure or ClojureScript code
- Setting up test infrastructure for CLJS projects
- Using shadow-cljs for compilation
- The user asks to "add Clojure tests" or "set up cljs.test"
- 测试Clojure或ClojureScript代码
- 为CLJS项目搭建测试基础设施
- 使用shadow-cljs进行编译
- 用户要求“添加Clojure测试”或“搭建cljs.test”
Do Not Use This Skill When
不适用场景
- Testing TypeScript/JavaScript code (use testing-typescript-vitest)
- Project uses a different Clojure test framework (midje, test.check)
- 测试TypeScript/JavaScript代码(请使用testing-typescript-vitest)
- 项目使用其他Clojure测试框架(midje、test.check)
ClojureScript Test Setup
ClojureScript测试搭建
shadow-cljs Configuration
shadow-cljs配置
clojure
;; shadow-cljs.edn
{:source-paths ["src" "test"]
:dependencies [[cider/cider-nrepl "0.28.5"]
[cider/orchard "0.11.0"]]
:builds {:test {:target :browser-test
:output-to "target/test/test.js"
:tests {:matches #".*-test$"}
:devtools {:http-port 8080
:http-resource-root "target/test"}}
:node-test {:target :node-test
:output-to "target/test/node-test.js"
:tests {:matches #".*-test$"}}}}clojure
;; shadow-cljs.edn
{:source-paths ["src" "test"]
:dependencies [[cider/cider-nrepl "0.28.5"]
[cider/orchard "0.11.0"]]
:builds {:test {:target :browser-test
:output-to "target/test/test.js"
:tests {:matches #".*-test$"}
:devtools {:http-port 8080
:http-resource-root "target/test"}}
:node-test {:target :node-test
:output-to "target/test/node-test.js"
:tests {:matches #".*-test$"}}}}package.json Scripts
package.json脚本
json
{
"scripts": {
"test:cljs": "shadow-cljs compile node-test && node target/test/node-test.js",
"test:browser": "shadow-cljs compile test && npx http-server target/test -p 8080",
"test:watch": "shadow-cljs watch test"
}
}json
{
"scripts": {
"test:cljs": "shadow-cljs compile node-test && node target/test/node-test.js",
"test:browser": "shadow-cljs compile test && npx http-server target/test -p 8080",
"test:watch": "shadow-cljs watch test"
}
}Basic cljs.test Syntax
cljs.test基础语法
clojure
(ns my-project.core-test
(:require [cljs.test :refer [deftest is testing are]]
[my-project.core :as core]))
(deftest add-test
(testing "addition"
(is (= (core/add 2 3) 5))
(is (= (core/add -1 1) 0))
(is (= (core/add 0 0) 0))))
(deftest subtract-test
(testing "subtraction"
(is (= (core/subtract 5 3) 2))
(is (= (core/subtract 3 5) -2))))
(deftest multiply-test
(testing "multiplication"
(are [x y] (= (core/multiply x y) (* x y))
2 3
-1 5
0 10)))clojure
(ns my-project.core-test
(:require [cljs.test :refer [deftest is testing are]]
[my-project.core :as core]))
(deftest add-test
(testing "addition"
(is (= (core/add 2 3) 5))
(is (= (core/add -1 1) 0))
(is (= (core/add 0 0) 0))))
(deftest subtract-test
(testing "subtraction"
(is (= (core/subtract 5 3) 2))
(is (= (core/subtract 3 5) -2))))
(deftest multiply-test
(testing "multiplication"
(are [x y] (= (core/multiply x y) (* x y))
2 3
-1 5
0 10)))Test Assertions
测试断言
clojure
(deftest assertion-examples
(testing "basic assertions"
(is true)
(is (= 1 1))
(is (not false)))
(testing "collection assertions"
(is (empty? []))
(is (seq [1 2 3]))
(is (contains? {:a 1} :a))
(is (contains? [1 2 3] 0)))
(testing "exception handling"
(is (thrown? js/Error
(throw (js/Error. "test")))))
(testing "approx assertions for floats"
(is (== 0.3 (+ 0.1 0.2)))))clojure
(deftest assertion-examples
(testing "basic assertions"
(is true)
(is (= 1 1))
(is (not false)))
(testing "collection assertions"
(is (empty? []))
(is (seq [1 2 3]))
(is (contains? {:a 1} :a))
(is (contains? [1 2 3] 0)))
(testing "exception handling"
(is (thrown? js/Error
(throw (js/Error. "test")))))
(testing "approx assertions for floats"
(is (== 0.3 (+ 0.1 0.2)))))Testing Async Code
异步代码测试
clojure
(ns my-project.async-test
(:require [cljs.test :refer [deftest is testing async]]
[my-project.async :as async]))
(deftest async-test
(async done
(async/timeout 100
(is true))
(done)))
(deftest promise-test
(async done
(-> (async/load-data)
(.then (fn [data]
(is (= (:status data) 200))
(done)))
(.catch (fn [err]
(is false "Should not error")
(done))))))clojure
(ns my-project.async-test
(:require [cljs.test :refer [deftest is testing async]]
[my-project.async :as async]))
(deftest async-test
(async done
(async/timeout 100
(is true))
(done)))
(deftest promise-test
(async done
(-> (async/load-data)
(.then (fn [data]
(is (= (:status data) 200))
(done)))
(.catch (fn [err]
(is false "Should not error")
(done))))))cljs-init-tests Macro
cljs-init-tests宏
The provides convenient initialization for tests:
cljs-init-testsclojure
(ns my-project.init-test
(:require [cljs-init-tests.core :refer [init-tests deftest-test]]
[my-project.math :as math]
[cljs.test :refer [deftest is testing]]))
;; Initialize test infrastructure
(init-tests)
;; Test definitions work normally
(deftest math-tests
(testing "basic math operations"
(is (= (math/add 2 3) 5))
(is (= (math/subtract 5 3) 2))))cljs-init-testsclojure
(ns my-project.init-test
(:require [cljs-init-tests.core :refer [init-tests deftest-test]]
[my-project.math :as math]
[cljs.test :refer [deftest is testing]]))
;; Initialize test infrastructure
(init-tests)
;; Test definitions work normally
(deftest math-tests
(testing "basic math operations"
(is (= (math/add 2 3) 5))
(is (= (math/subtract 5 3) 2))))Setup and Fixtures
测试前置与夹具
clojure
(ns my-project.fixtures-test
(:require [cljs.test :refer [deftest use-fixtures testing]]
[my-project.db :as db]))
;; Define fixtures
(defn setup-db [f]
(db/reset!)
(f)
(db/cleanup!))
(defn with-logging [f]
(println "Starting test")
(f)
(println "Finished test"))
;; Use fixtures
(use-fixtures :once setup-db)
(use-fixtures :each with-logging)
(deftest database-test
(testing "database operations"
(is (some? (db/connect)))
(is (db/insert {:name "test"}))))clojure
(ns my-project.fixtures-test
(:require [cljs.test :refer [deftest use-fixtures testing]]
[my-project.db :as db]))
;; Define fixtures
(defn setup-db [f]
(db/reset!)
(f)
(db/cleanup!))
(defn with-logging [f]
(println "Starting test")
(f)
(println "Finished test"))
;; Use fixtures
(use-fixtures :once setup-db)
(use-fixtures :each with-logging)
(deftest database-test
(testing "database operations"
(is (some? (db/connect)))
(is (db/insert {:name "test"}))))Testing CLJS-Specific Features
CLJS专属特性测试
clojure
(ns my-project.cljs-specific-test
(:require [cljs.test :refer [deftest is testing]]
[cljs.core :as c]))
(deftest atom-test
(let [counter (atom 0)]
(swap! counter inc)
(is (= @counter 1))
(swap! counter inc)
(is (= @counter 2))))
(deftest reagent-test
(let [component (fn []
[:div "Hello"])]
(is (fn? component))))
(deftest protocol-test
(let [record (->Record. :field)]
(is (= (:field record) :field))))clojure
(ns my-project.cljs-specific-test
(:require [cljs.test :refer [deftest is testing]]
[cljs.core :as c]))
(deftest atom-test
(let [counter (atom 0)]
(swap! counter inc)
(is (= @counter 1))
(swap! counter inc)
(is (= @counter 2))))
(deftest reagent-test
(let [component (fn []
[:div "Hello"])]
(is (fn? component))))
(deftest protocol-test
(let [record (->Record. :field)]
(is (= (:field record) :field))))Shadow-cljs Test Compilation
Shadow-cljs测试编译
Test Build Output
测试构建输出
bash
undefinedbash
undefinedCompile for Node.js
Compile for Node.js
shadow-cljs compile node-test
shadow-cljs compile node-test
Compile for browser
Compile for browser
shadow-cljs compile test
shadow-cljs compile test
Watch and test
Watch and test
shadow-cljs watch test
undefinedshadow-cljs watch test
undefinedCI/CD Integration
CI/CD集成
bash
#!/bin/bashbash
#!/bin/bashrun-cljs-tests.sh
run-cljs-tests.sh
set -e
set -e
Install dependencies
Install dependencies
yarn install
yarn install
Compile tests
Compile tests
shadow-cljs compile node-test
shadow-cljs compile node-test
Run tests
Run tests
node target/test/node-test.js
node target/test/node-test.js
Check exit code
Check exit code
if [ $? -eq 0 ]; then
echo "Tests passed!"
exit 0
else
echo "Tests failed!"
exit 1
fi
undefinedif [ $? -eq 0 ]; then
echo "Tests passed!"
exit 0
else
echo "Tests failed!"
exit 1
fi
undefinedOrganization
代码组织
src/
└── my_project/
├── core.cljs
└── core_test.cljs # Test in same namespace
test/
└── my_project/
├── integration_test.cljs
└── e2e_test.cljssrc/
└── my_project/
├── core.cljs
└── core_test.cljs # Test in same namespace
test/
└── my_project/
├── integration_test.cljs
└── e2e_test.cljsBest Practices
最佳实践
1. Test Naming
1. 测试命名
clojure
;; GOOD - descriptive test names
(deftest add-two-positive-numbers-returns-sum)
(deftest handle-empty-input-gracefully)
;; BAD - vague names
(deftest test-add)
(deftest test-stuff)clojure
;; GOOD - descriptive test names
(deftest add-two-positive-numbers-returns-sum)
(deftest handle-empty-input-gracefully)
;; BAD - vague names
(deftest test-add)
(deftest test-stuff)2. Test Organization
2. 测试组织
clojure
(deftest arithmetic-tests
(testing "addition"
(is (= (+ 2 3) 5))
(is (= (+ 0 0) 0)))
(testing "subtraction"
(is (= (- 5 3) 2))))clojure
(deftest arithmetic-tests
(testing "addition"
(is (= (+ 2 3) 5))
(is (= (+ 0 0) 0)))
(testing "subtraction"
(is (= (- 5 3) 2))))3. Property-Based Testing
3. 基于属性的测试
clojure
;; With test.check
(deftest sort-is-idempotent
(let [gen (gen/vector gen/int)]
(is (forall [v gen]
(= (sort v) (sort (sort v)))))))clojure
;; With test.check
(deftest sort-is-idempotent
(let [gen (gen/vector gen/int)]
(is (forall [v gen]
(= (sort v) (sort (sort v)))))))Running Tests
运行测试
| Command | Purpose |
|---|---|
| Compile for browser |
| Compile for Node.js |
| Watch and test |
| Run tests via CLI |
| 命令 | 用途 |
|---|---|
| 为浏览器编译测试代码 |
| 为Node.js编译测试代码 |
| 监听文件变化并自动测试 |
| 通过CLI运行测试 |
Output
输出内容
- shadow-cljs.edn configuration
- Test namespace setup with cljs.test
- Example test files for CLJS
- Fixtures and setup patterns
- CI/CD test script
- shadow-cljs.edn配置文件
- 使用cljs.test搭建的测试命名空间
- CLJS示例测试文件
- 夹具与测试前置模式
- CI/CD测试脚本
References
参考资料
- cljs.test: https://cljs.github.io/api/cljs.test/
- shadow-cljs: https://shadow-cljs.github.io/docs/
- cljs-init-tests: https://github.com/Olical/cljs-init-tests
- test.check: https://github.com/clojure/test.check
- cljs.test: https://cljs.github.io/api/cljs.test/
- shadow-cljs: https://shadow-cljs.github.io/docs/
- cljs-init-tests: https://github.com/Olical/cljs-init-tests
- test.check: https://github.com/clojure/test/check