EzDevInfo.com

Midje

Midje provides a migration path from clojure.test to a more flexible, readable, abstract, and gracious style of testing

How is 'provided' implemented in a fact in Midje?

I was reading Clojure in Action chapter 8 about TDD and experimented with the stubbing macro. It uses the dynamic binding mechanism to stub functions. Alas, in Clojure 1.3 it is not possible to use the binding mechanism for non-dynamic vars, so the stubbing macro doesn't work in most cases, unless you explicitly declare the var which points to a function dynamic. Then I wondered how stubbing is done in Midje and tried to find the source for 'provided', but I couldn't find it. So here it goes:

How is 'provided' implemented in a fact in Midje? Can someone explain this in detail?


Source: (StackOverflow)

Midje provided not stubbing function in Compojure / Ring handler

I'm attempting to use Midje to stub the view in a handler unit test, but my use of Midje's (provided) obviously isn't correct.

I've simplified and inlined the view to a (content) function in the handler:

(ns whattodo.handler
  (:use compojure.core)
  (:require [whattodo.views :as views]))

(defn content [] (views/index))

(defn index [] (content))

(defroutes app
  (GET "/" [] (index)))

and am trying to test it using

(ns whattodo.t-handler
  (:use midje.sweet)
  (:use ring.mock.request)
  (:use whattodo.handler))

(facts "It returns response"
       (let [response (app (request :get "/"))]
         (fact "renders index view" (:body response) => "fake-html"
               (provided (#'whattodo.handler/content) => (fn [] "fake-html")))))

I was expecting the stubbed function to be called returning 'fake-html' and thus the unit test passing, but instead, the test fails as the real implementation is called - invoking the real view.


Source: (StackOverflow)

Advertisements

Setup and teardown temporary directory for a midje fact

This is the skeleton of what I want to achieve

(let [temp-dir (create-temp-dir)]          ; setup
  (fact
    (do-something-with temp-dir) => true)  ; actual test
  (delete-dir temp-dir))                   ; teardown

The midje testing framework gives access to lexical scope (scroll down towards the end). So this is what I'd expect to work:

(against-background
  (around :facts
    (let [temp-dir (create-temp-dir)]
      (do ?form (delete-dir temp-dir))))
  (fact (do-something-with temp-dir) => true))

But the compiler complains that it can't resolve the symbol temp-dir. Any idea how to make this work?


Source: (StackOverflow)

Testing filesystem code

Unit-testing with Midje is a great experience, but now I need to test some code which interacts with the filessytem. Specifically, the code builds a data structure representation from a local directory layout.

Something that comes to mind is creating directories and files in /tmp, which then have to be cleaned up after the tests. I probably could make it work but it would be much better if there were a Right Way to do it.

What is the preferred way to test filesystem code, in Clojure or more generally?


Source: (StackOverflow)

Midje print stacktrace when test fails

I am learning Clojure, and trying to use TDD to do so *.

I use midje as a testing library. Love it so far, the expected versus actual results display is very helpfull.

But is there was a way to use clojure.tools.trace or something similar to print the trace of the first test that fails ?

*: Specifically, I remember seeing a talk by Robert C. Martin about the transformation priority premise, and I'm implementing a factorial function this way. There isn't yet much code to show though.


Source: (StackOverflow)

how can lein midje :autotest be made to work with immutant?

I'm migrating a application I did in ring over to immutant and and a bit lost as to what to do with all my tests.

Because immutant projects are required to be deployed, what is the best strategy to test the functionality?


Source: (StackOverflow)

Dynamically calculated description of a midje fact

I want to write a function to factor out some common facts, like this

(defn check-odd-and-positive
  [n]
  (fact (str n " not odd") n => odd?)
  (fact (str n " not positive") n => positive?))

(facts "about the answer"
  (check-odd-and-positive 42))

But it doesn't result in "42 not odd" as the description of the fact. I know a similar effect could be achieved with tabular facts, but I want to be able to share such a fact among fact groups.


Source: (StackOverflow)

Mocking protocol implementations in Midje

Is there any way to mock (not stub) a protocol function with Midje (clojure) using something like the "provided" syntax?

This is simial to the question in: Mocking Clojure protocols, but with mocking.

In more detail: I have a protocol and a function that returns something that implements it. I would like to stub the function to return a mock of the protocol and I would like to register an expectation on one of the functions of the mocked protocol "implementation".

edit - here is an example:

There is a protocol and it's implementation:

(defprotocol Thiny (go-bump [_ _]))
(deftype TheThing []
  Thiny
  (go-bump [_ _] 23))

There is a function that returns an implementation of a protocol:

(defn gimme [] (TheThing.))

TheThing might be a DB or network connection or some other nasty thing you want to get rid of in the test.

Then, there is the function I want to test:

(defn test-me [n]
  (let [t (gimme)]
    (-> t (go-bump n))))

I want to make sure it calls go-bump with n.

This is my first attempt to create a test. But it is only halfway done, I would like to setup expectations on the Thiny returned by gimme:

(fact
  (test-me 42) => 42
  (provided (gimme) => (reify Thiny (go-bump [_ n] n))))

Source: (StackOverflow)

How do I test futures in clojure?

I'm trying to use midje to test a future, but I can't seem to get it to work.

The code looks like

(defn foo []
  (let [f (future (bar))]
    (baz @f))

With a test like

(fact 
  (foo) => ..a..
  (provided
    (bar) => ..b..
    (baz ..b..) => ..a..))

This fails, saying that bar never gets called. Any way around this?


Source: (StackOverflow)

Faking friend credential function using Midje

I'm trying to test my routing in isolation using Midje. For some routes that hit the database I have no trouble using (provided ...) to isolate the route from a real db call. I've introduced Friend for authentication and I've been unable to fake the call to the credential function.

My credential function looks like this (It's implemented like this because I don't want it getting called just yet):

(defn cred-fn
  [creds]
  (println (str "hey look I got called with " creds))
  (throw (Exception.)))

The middleware for the routes then look like this:

(def app 
  (-> app-routes
      (wrap-json-body {:keywords? true :bigdecimals? true})
      wrap-json-response
      (wrap-defaults defaults)
      (friend/authenticate
       {:unauthorized-handler json-auth/login-failed
        :workflows [(json-auth/json-login
                     :login-uri "/login"
                     :login-failure-handler json-auth/login-failed
                     :credential-fn auth/cred-fn)]})
      (ring-session/wrap-session)))

I've also tried without using the auth-json-workflow, the implementation for the routes looks almost identical and I can add that if it helps but I get the same result.

And then my tests look like this (using ring-mock):

(defn post [url body]
  (-> (mock/request :post url body)
      (mock/content-type "application/json")
      app))

(fact "login with incorrect username and password returns unauthenticated"
  (:status (post "/login" invalid-auth-account-json)) => 401
  (provided
    (auth/cred-fn anything) => nil))
(fact "login with correct username and password returns success"
  (:status (post "/login" auth-account-json)) => 200
  (provided
    (auth/cred-fn anything) => {:identity "root"}))

I then get the following output running the tests:

hey look I got called with {:password "admin_password", :username "not-a-user"}
FAIL at (handler.clj:66)
These calls were not made the right number of times:
    (auth/cred-fn anything) [expected at least once, actually never called]
FAIL "routes - authenticated routes - login with incorrect username and password returns unauthenticated" at (handler.clj:64)
    Expected: 401
      Actual: java.lang.Exception
          clojure_api_seed.authentication$cred_fn.invoke(authentication.clj:23)

hey look I got called with {:password "admin_password", :username "root"}
FAIL at (handler.clj:70)
These calls were not made the right number of times:
    (auth/cred-fn anything) [expected at least once, actually never called]

FAIL "routes - authenticated routes - login with correct username and password returns success" at (handler.clj:68)
    Expected: 200
      Actual: java.lang.Exception
          clojure_api_seed.authentication$cred_fn.invoke(authentication.clj:23)

So from what I can see the provided statement is not taking effect, and I'm not sure why. Any ideas?


Source: (StackOverflow)

Midje, provided not working as I expect

I have written the following Midje test:

(fact (followers-minus-friends ...name...) => ["Dude"]
      (provided (idset show-followers ...name...) => #{1 2 3}
                (idset show-friends ...name...) => #{1 2}
                (userinfos #{3}) => [{:screen_name "Dude"}]))

to test the following function (in a different namespace):

(defn followers-minus-friends [screenname]
  (let [difference-ids (difference (idset show-followers screenname)
                                   (idset show-friends screenname))
        userinfos (userinfos difference-ids)]
    (map :screen_name userinfos)))

The test may seem pretty useless, but I'm just trying to get accustomed to Midje. Somehow, the function idset just gets executed, which I wanted to prevent by providing a return value in the provided-clause. What could be an explanation for this?

EDIT: I have uploaded the project to Github here, in case you want to try to reproduce the above situation: https://github.com/Borkdude/twitter-utils


Source: (StackOverflow)

Passing data to a liberator post endpoint in midje test using ring-mock

I am trying to write a midje test using ring-mock to do a post to a liberator endpoint. I can successfully write a test for get requests but I can't seem to pass data to the post, I only get back the malformed response. Here is the meat of the code that I have.

;; ====
; Resource
;; ====
(def users (atom [{:id 1 :name "User One"} {:id 2 :name "User Two"}]))

(defn malformed-users? [context]
  (let [params (get-in context [:request :multipart-params])]
    (and
      (empty? (get params "id"))
      (= (get-in context [:request :request-method]) :post))))

(defresource all-users []
  :allowed-methods [:get :post]
  :available-media-types ["application/json"]
  :handle-ok (fn [_] {:users @users})
  :malformed? (fn [context] (malformed-users? context))
  :handle-malformed "You need to pass both a valid name and id"
  :post! (fn [context]
           (let [params (get-in context [:request :multipart-params])]
             (swap! users conj {:id (bigint (get params "id")) :name (get params "name")})))
  :handle-created (fn [_] {:users @users}))

(defroutes user-routes
  (ANY "/users" [_] (all-users)))


;; ====
; Test
;; ====
(fact "Get request to users endpoint returns desired content"
  (let [response (user-routes (mock/request :post "/users" {:id "3" :name "TestGuy"}))]
    (:status response) => 201
    (get-in response [:headers "Content-Type"]) => "application/json;charset=UTF-8"))

Source: (StackOverflow)

leiningen midje tests not working in Intellij

Consider the following (minimal) leiningen project

./project.clj:

(defproject repro "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.5.1"]
                 [midje               "1.5.1"]])

./repro/src/repro/core.clj:

(ns repro.core)

./repro/test/repro/core_test.clj:

(ns repro.core-test
  (:require [repro.core  :refer :all]
            [midje.sweet :refer :all]))

(facts "about numbers"
       (fact "trivial"
         1 => 1) )

If I have the leiningen midje plugin installed, this runs at the command prompt as follows:

lein clean
lein midje
~~> All checks (1) succeeded.

However, if I import the leiningen project into Intellij 12.1.5 Community Edition, I get a fat stack trace:

Exception in thread "main" java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:270)
    ...
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.NullPointerException
at java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:333)
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:988)
at clojure.lang.Namespace.find(Namespace.java:188)
at clojure.core$find_ns.invoke(core.clj:3728)
at clojure.core$the_ns.invoke(core.clj:3760)
at clojure.core$ns_name.invoke(core.clj:3767)
at midje.Bootstrap$bootstrap.invoke(Bootstrap.clj:8)
at midje.sweet__init.load(Unknown Source)
at midje.sweet__init.<clinit>(Unknown Source)
... 37 more

Looks like La Clojure + Intellij can't find some of midje's prerequisites, which is odd, because La Clojure is running classpaths out of the leiningen .m2 directory.

I've looked for a midje plugin for Intellij, but no luck so far.

I need this because although I am happy to use just emacs + leiningen, my team wants Intellij.


Source: (StackOverflow)

Why can't I use midge to mock a function that throws using slingshot's throw+

Here's the situation: I'm trying to unit test function A that calls function B. Function B is called in a slingshot try+ block and under certain circumstances it can throw using a slingshot throw+. I want to mock function B in a midje test so that it returns something that the catch in the try+ block will actually catch. I can't seem to create the right thing to throw though. Here's a substantially abbreviated sketch of the code and the test:

(defn function-A
  [param]
  (try+
    (function-B param)
    (catch [:type :user-not-found]
      (do-something))))

(defn function-B
  [param]
  (throw+ [:type :user-not-found]))

(fact "do-something is called"
  (function-A "param") => (whatever is the result of calling do-something)
  (provided
    (function-B "param") =throws=> (clojure.lang.ExceptionInfo. "throw+: {:type :user-not-found}"
                                                                {:object {:type :user-not-found}, :environment {}}
                                                                nil)))

The ExceptionInfo that I'm throwing seems to be roughtly the right thing. I can see this when my application is running through numerous prn statements. However, whatever I try, I can't get the test to work.

I also tried the bit of code below in a repl to see whether I could understand the problem. However, whilst both pieces of code seem to involve identical Exceptions, only one (the pure slingshot one) manages to catch and print "caught it". I think that if I could understand why one works and the other doesn't, I would be able to solve the problem with the unit test.

(try+
  (try
    (throw+ {:type :user-not-found})
    (catch Exception e
      (prn "Caught:  " e)
      (prn "Class:   " (.getClass e))
      (prn "Message: " (.getMessage e))
      (prn "Cause:   " (.getCause e))
      (prn "Data:    " (.getData e))
      (throw e)))
  (catch [:type :user-not-found] p
    (prn "caught it")))

(try+
  (try
    (throw (clojure.lang.ExceptionInfo. "throw+: {:type :user-not-found}"
                                        {:object {:type :user-not-found}, :environment {}}
                                        nil))
    (catch Exception e
      (prn "Caught:  " e)
      (prn "Class:   " (.getClass e))
      (prn "Message: " (.getMessage e))
      (prn "Cause:   " (.getCause e))
      (prn "Data:    " (.getData e))
      (throw e)))
  (catch [:type :user-not-found] p
    (prn "caught it")))

Source: (StackOverflow)

Midje on travis-ci fails with NoSuchMethodError: KeywordLookupSite.

I'm trying to use the Midje testing framework for Clojure on the Travis CI service.

The project.clj looks like this:

(defproject my-project "0.1.0-SNAPSHOT"
  :description "Example"
  :dependencies [[org.clojure/clojure "1.3.0"]]
  :dev-dependencies [[midje "1.3.0"]
                     [lein-midje "1.0.7"]])

I added a .travis.yml file:

language: clojure
script: "lein midje"

Running lein midje locally (Ubuntu 11.10) works fine, but on Travis CI the build fails with the following exception:

Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodError: clojure.lang.KeywordLookupSite.<init>(ILclojure/lang/Keyword;)V
at clojure.lang.Util.runtimeException(Util.java:165)
at clojure.lang.Compiler.eval(Compiler.java:6476)
at clojure.lang.Compiler.eval(Compiler.java:6431)
at clojure.core$eval.invoke(core.clj:2795)
at clojure.main$eval_opt.invoke(main.clj:296)
at clojure.main$initialize.invoke(main.clj:315)
at clojure.main$script_opt.invoke(main.clj:339)
at clojure.main$main.doInvoke(main.clj:426)
at clojure.lang.RestFn.invoke(RestFn.java:482)
at clojure.lang.Var.invoke(Var.java:417)
at clojure.lang.AFn.applyToHelper(AFn.java:178)
at clojure.lang.Var.applyTo(Var.java:518)
at clojure.main.main(main.java:37)
Caused by: java.lang.NoSuchMethodError: clojure.lang.KeywordLookupSite.<init>(ILclojure/lang/Keyword;)V
at leiningen.util.paths$native_arch_path.<clinit>(paths.clj:32)
at leiningen.util.paths__init.load(Unknown Source)
at leiningen.util.paths__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at clojure.lang.RT.loadClassForName(RT.java:2030)
at clojure.lang.RT.load(RT.java:417)
at clojure.lang.RT.load(RT.java:398)
at clojure.core$load$fn__4610.invoke(core.clj:5386)at clojure.core$load.doInvoke(core.clj:5385)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5200)
at clojure.core$load_lib.doInvoke(core.clj:5237)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:602)
at clojure.core$load_libs.doInvoke(core.clj:5271)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:602)
at clojure.core$require.doInvoke(core.clj:5352)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at leiningen.core$loading__4414__auto__.invoke(core.clj:1)
at leiningen.core__init.load(Unknown Source)
at leiningen.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at clojure.lang.RT.loadClassForName(RT.java:2030)
at clojure.lang.RT.load(RT.java:417)
at clojure.lang.RT.load(RT.java:398)
at clojure.core$load$fn__4610.invoke(core.clj:5386)
at clojure.core$load.doInvoke(core.clj:5385)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5200)
at clojure.core$load_lib.doInvoke(core.clj:5237)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:602)
at clojure.core$load_libs.doInvoke(core.clj:5271)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:604)
at clojure.core$use.doInvoke(core.clj:5363)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at user$eval1.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6465)
... 11 more

Why does the error occur on Travis CI, but not my machine? What can I do to fix this?


Source: (StackOverflow)