测试CRUD Clojure函数,例如使用ruby Rspec

时间:2018-07-30 21:10:21

标签: clojure clojure.spec

我刚完成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中的DB(CRUD)部分。我什至不知道将规范文件放在哪里。我看到了类似于FactoryGirl的Clojure库,但是我不知道是否应该使用spec创建自己的数据结构,因此我不确定从哪里开始,这里有clojure.test.check.generators和spec生成器,但是我不知道知道它们是否不同,或者我应该只使用spec而不使用clojure.test.check。我可以从命令行而不是在REPL内部运行测试吗?

我的意思是:是否有有关如何测试一组CRUD功能的文档或教程?我想我只需要最初的HOWTO,然后就可以从那儿取下来,我将为像我这样的新手编写一个教程。

已更新

似乎我要寻找Midje:

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

3 个答案:

答案 0 :(得分: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))

答案 1 :(得分: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})))))))

答案 2 :(得分:0)