对于 IntelliJ/Cursive,为什么 clojure.test.is 认为空字符串等于任何字符串?

With IntelliJ/Cursive, why does clojure.test.is consider that empty-string equals any string?

使用 Intellij(v.2021.3.2)和 Cursive(v.1.12.1-2021.3)“运行 测试”功能(测试或命名空间上的绿色 运行 箭头), Clojure 中的一个简单单元测试在发现 "X" 等于 "".

时通过

完整示例:

    (ns my-test
      (:require [clojure.test :refer [deftest is run-tests]]))
    
    (deftest compare-empty
      (is (= "X" "")))

前言

首先,我总是建议从命令行 运行ning 测试,而不是从 IDE

可能的原因和解决方案

一个测试很容易不小心成为运行。总是困扰我的一种常见方式是,如果我不小心 re-used 两次不同的测试使用相同的名称。就像 Clojure Var 一样,第二个将替换第一个声明。

下面的测试如果是运行肯定会失败,看起来像:

(deftest t-string
  (is (= "X" "")))

结果

> lein clean ; lein test

--------------------------------------
   Clojure 1.11.1    Java 1.8.0_322
--------------------------------------

Testing tst.demo.core

FAIL in (t-string) (core.clj:11)
expected: (= "X" "")
  actual: (not (= "X" ""))

Testing tst.demo.other

Ran 3 tests containing 4 assertions.
1 failures, 0 errors.

Failed 1 of 4 assertions

此外,请注意在 re-running 之前始终“清理”很重要,因为错误有时会使您使用与最新源代码不同的旧编译字节码。我为此使用别名:

alias lct='time (lein do clean, test)'

但是,考虑剪切和粘贴错误:

(deftest t-string
  (is (= "X" "")))

(deftest t-string
  (is (= "X" "X")))

结果

> lein clean ; lein test

:reloading (tst.demo.core)

Testing _bootstrap

--------------------------------------
   Clojure 1.11.1    Java 1.8.0_322
--------------------------------------

Testing tst.demo.core

Testing tst.demo.other

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

改进的解决方案

因此,您可能对扩展库 tupelo.test 感兴趣(有关示例,请参见 this template project)。它将 auto-generate 唯一的测试名称,所以你可以这样写代码:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(dotest
  (is= "X" ""))

(dotest
  (is= "X" "X"))

结果

lein test tst.demo.core

lein test :only tst.demo.core/dotest-line-4

FAIL in (dotest-line-4) (core.clj:5)
expected: (clojure.core/= "X" "")
  actual: (not (clojure.core/= "X" ""))

lein test tst.demo.other

Ran 4 tests containing 5 assertions.
1 failures, 0 errors.
Tests failed.
( lein do clean, test; )  36.72s user 1.73s system 308% cpu 12.474 total

另请注意,tupelo.test 包括 is=isnt=

等便利功能
(is-nonblank= "hello " "   hello") ; => true

根据 OP 的说法,升级到最新的 Cursive 版本(在他们的例子中是 1.12.3-2021.3)解决了这个问题。