marick / Midje

Midje provides a migration path from clojure.test to a more flexible, readable, abstract, and gracious style of testing
MIT License
1.68k stars 128 forks source link

Cannot use prerequisites for functions with type hinted vars #466

Open viebel opened 4 years ago

viebel commented 4 years ago

I couldn't find a way to use prerequisites for functions with type hinted vars. The root cause is related to how type hint works and it comes down to some limitation of with-redefs as explained in #295.

However, as a midje user I am expecting some workaround (when using with-redefs the workaround is to type hint the mocking function).

Can someone think of a way to define prerequisites for the following scenario?

There is a workaround exposed here but it requires to modify the code of the function that is tested which is not desirable in my case.

Can someone think of a workaround (or maybe a fix in midje) that will allow me to use prerequisites for type hinted functions without modifying the source code.

Here is a simple illustration of my use case:

This code causes an exception:

(defn bar [^String x ^long x])
(defn foo []
  (bar "a" 1))

(fact
 (foo ) => nil
 (provided (bar "a" 1) => nil))
java.lang.ClassCastException: clojure.lang.AFunction$1 cannot be cast to clojure.lang.IFn$OLO

While this code works as expected

(defn bar [^String x ^long x])
(defn foo []
  (#'bar "a" 1))

(fact
 (foo ) => nil
 (provided (bar "a" 1) => nil))
viebel commented 3 years ago

Could anyone help on this one?

philomates commented 3 years ago

I can confirm that this issue is also present in mockfn, which is a test-framework agnostic reimplementation of the best parts (in my opinion) of Midje's mocking capabilities

If you want to explore coming up with a fix for this, I would recommend trying to get it going in that project because it has a much smaller codebase than Midje

to reproduce there:

(ns mockfn.scratch
  (:require [mockfn.macros :refer [providing]]))

(defn bar [^String x ^long x])
(defn foo []
  (bar "a" 1))

(providing [(bar "a" 1) nil]
 (foo))

This is a cornercase that seems to be a nuance of how Clojure is implemented (as far as I understand), so I personally don't plan to dive into this at the moment.