practicalli / clojure-web-services

Develop production grade server-side web services and APIs using Clojure and REPL driven development
https://practical.li/clojure-web-services
Creative Commons Attribution Share Alike 4.0 International
11 stars 14 forks source link

Compojure-api testing #2

Open practicalli-johnny opened 6 years ago

practicalli-johnny commented 6 years ago

trouble testing routes in an app that uses compojure-api. One of the handlers is asynchronous and returns a channel. The server runs fine, but when running tests the async handler produces the following exception:


java.lang.IllegalArgumentException: No implementation of method: :render of protocol: #'compojure.response/Renderable found for class: clojure.core.async.impl.channels.ManyToManyChannel```
(edited)
Since i’m using lein-ring to run the server and build the uberjar and it works fine under those conditions, I assume I’ve missed some bit of configuration in the tests. If anyone could point me in the direction of some docs (or a solution!) it’d be much appreciated. I can’t find anything that looks relevant on the repos for compojure-api or ring
practicalli-johnny commented 6 years ago

there is a source file somewhere that extends the Renderable protocol to a channel, and I bet that source file is loaded in the machinery that lein-ring generates, but not otherwise, so when run outside of lein ring (when testing) you get that error. so if you look through the compojure sources and find that file, and make sure to require that namespace in your tests, I suspect it will work

practicalli-johnny commented 6 years ago

fwiw it looks like the options for getting around the Renderable error i was receiving are to provide an extension of the compojure.response.Renderable protocol for testing purposes, or to call the handler with respond and raise callbacks in the test code. Compojure-api provides implementations of compojure.response.Sendable for channels and aleph deferreds, but does not provide implementations for Renderable (which makes sense i think since it looks like Sendable is supposed to be for async while Renderable is for sync…). When using lein-ring you can tell the plugin to treat the handler as async which has it start a server with the :async? option set to true and I assume that makes it pass all requests with respond and raise, which makes compojure use the Sendable protocol, which is why the server ran fine while my test that used the handler with only a request argument (thus triggering the Renderable protocol) failed.

practicalli-johnny commented 6 years ago

common trick on ring-cps testing is to create the respond and raise as (promise) and deref with timeout.