2

我刚刚完成了使用 Clojure 的前六周工作,到目前为止,我对这种语言非常满意。我正在使用 leiningen 和 PostgreSQL 开发我的个人博客。我已经可以发布新内容、上传文件并且我有会话、cookie 和角色,无论如何我认为此时我有足够的代码开始担心测试部分,但我有点卡住了,因为看起来很多clojure 的测试和规范方面正在发生一些事情。

所以我有这个功能:

(defn download
  "GET /admin/uploads/download/:id"
 [params]
 (let [id       (-> params :id)
       upload   (model-upload/get-upload id)
       filename (:filename upload)
       body     (clojure.java.io/file (str "public/uploads/" filename))]
{:status 200
 :body body
 :headers {"Content-Type" "application/pdf"
           "Content-Length" (str (.length body))
           "Cache-Control" "no-cache"
           "Content-Disposition" (str "attachment; filename=" filename)}}))

该函数将地图作为参数,并提供最终地图以由 compojure 发送和处理。我来自 Rails 世界,因此在 Rails 中测试此功能的方法是创建一个 FactoryGirl 类,使用经典创建一个 Rspec 模型文件:

 expect(first_map).to eq(map_returned_by_function)

在其中比较预期的内容,然后从命令行运行 rspec 以获得绿线或红线。

从昨天开始,我正在尝试使用此文档使用 Clojure 复制该过程:

https://www.codesai.com/2018/03/kata-generating-bingo-cards

但我认为目前还没有一种“标准”的方式来进行测试,包括 Clojure 中的数据库(CRUD)部分。我什至不知道将规范文件放在哪里。我看到类似于 FactoryGirl 的 Clojure 库,但我不知道是否应该使用规范创建自己的数据结构,所以我不确定从哪里开始,有 clojure.test.check.generators 和规范生成器,但我不知道知道它们是否不同,或者我是否应该只使用规范而不是 clojure.test.check。我可以从命令行而不是在 REPL 中运行测试吗?

我的意思是:是否有关于如何测试一组 CRUD 功能的文档或教程?我想我只需要最初的 HOWTO,然后我可以从那里拿走它,我会为像我这样的新手写一个教程。

更新:

看起来 Midje 是我正在寻找的东西:

https://github.com/marick/Midje/wiki/A-tutorial-introduction

4

3 回答 3

2

在 Clojure 中,将 IO 推送到应用程序的边缘是惯用的做法。不是从下载函数中的数据库读取,而是将从数据库读取的数据传递到参数映射中的下载函数中。然后针对纯部分编写测试。

你的函数最终看起来像这样:

(defn download-without-db
"GET /admin/uploads/download/:id"
 [params]
 (let [upload   (-> params :upload)
       filename (:filename upload)
       body     (clojure.java.io/file (str "public/uploads/" filename))]
{:status 200
 :body body
 :headers {"Content-Type" "application/pdf"
           "Content-Length" (str (.length body))
           "Cache-Control" "no-cache"
           "Content-Disposition" (str "attachment; filename=" filename)}}))

(defn get-upload-from-db [params]
    (assoc params :upload (-> params :id model-upload/get-upload)))

(defn download [params]
    (-> params 
        get-upload-from-db
        download-without-db))
于 2018-08-01T00:05:53.787 回答
1

您只是在寻找clojure.test。它甚至在其文档中提到了与 RSpec 的关系。

这是 Clojure 本身的一部分,不需要依赖项,我建议您在使用像 Midje 这样的非标准测试框架之前先熟悉它,因为它是 Clojure 的事实上的测试框架,也是最受欢迎的一个.

你会这样写一个测试:

(deftest download
  (testing "With valid input"
    (testing "it should return a header map with filename included"
      (is (= first_map (unit/download {:id 1}))))))

现在,Clojure 不是面向对象的,因此没有要模拟的对象。也就是说,您经常在 Clojure 中使用 Java 表单,而 Java 提供了类和对象。如果您想轻松地模拟它们,可以使用名为Mockito的 Java 模拟框架。

但是,在您的情况下,该download函数不使用任何 Java 对象。所以你也不需要。

现在,如果您希望这是一个集成测试,那么我编写的测试对您来说已经足够了。如果您希望这是一个单元测试,并且我假设(model-upload/get-upload id)会进行一些 IO,那么您将需要模拟该model-upload/get-upload功能。您可以使用with-redefs-fn轻松做到这一点:

(deftest download
  (testing "With valid input"
    (testing "it should return a header map with filename included"
      (with-redefs-fn {#'model-upload/get-upload (constantly {:filename "cool.pdf"})}
        (is (= first_map (unit/download {:id 1})))))))

或者您可以使用with-redefs

(deftest download
  (with-redefs [model-upload/get-upload (constantly {:filename "cool.pdf"})]
    (testing "With valid input"
      (testing "it should return a header map with filename included"
        (is (= first_map (unit/download {:id 1})))))))
于 2018-08-08T06:16:10.013 回答