アクセス制御を回避して、プライベート関数をテストする方法
プライベート関数をVarに変換してアクセスすれば、他のパッケージから呼び出し可能。参考
- プライベート関数を定義
(ns private-test.core)
(defn- a-private-func []
(println "called a private function."))
- ユニットテストから呼び出し
(ns private-test.core-test
(:require [expectations :refer :all]
[private-test.core :refer :all]))
(expect nil
(a-private-func))
Error refreshing environment: java.lang.RuntimeException: Unable to resolve symbol: a-private-func in this context, compiling:(private_test/core_test.clj:6:3)
- 完全パッケージ名をつけても同様に失敗
(expect nil
(private-test.core/a-private-func))
-
#'
をつけると、異なる名前空間からでもプライベート関数の呼び出しが可能
(expect nil
(#'private-test.core/a-private-func))
なぜこんなことが可能なのか
-
#'
(Var quote)は(var x)
の省略記法。private-test.core/a-private-func
はシンボル(clojure.lang.Symbol)であるが、Var quoteによってvar (clojure.lang.Var)に変換されている。プライベート関数のアクセス制限はシンボル内の:private
メタデータで行われているため、varに変換されるとその制限は外れる。
(meta #'private-test.core/a-private-func)
=>
{:private true, :ns #<Namespace private-test.core>, :name a-private-func, :file "private_test/core.clj", :column 1, :line 3, :arglists ([])}