Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Other by

In my application I'd like mock things like every possible response a REST call could return. This is not only for testing but also to demonstrate different behaviour while running my application.
For example, I had a requirement that my frontend performs an health check against the backend and if it fails, it will display a message that says that no service is available. I now want a mock health check that always fails, so that I can demonstrate the message.
There are three approaches that come to my mind.

  1. Protocols
  2. Different source-paths
  3. Higher order functions

Does anybody have experience with some of them? If so, what are the upsides/drawbacks of each? Am I missing something?

2 Answers

+1 vote

You try to compose your application in a way where mocking is rarely required, i.e. most of your functions are pure.

In your case it means you'll have a function that gets an object that represents a failure and have that function (either directly or indirectly) display a message.

Preferably, the function just does one thing: gets a failure object, returns an effect (or dispatches an event).

Now you don't need to mock anything, just run a test with the regular health check result and a failure result and check the outcome.

There's also the wonderful with-redef macro, that allows you to temporarily re-bind things.
In this example, http/post has been re-defined:

(deftest is-a-macro
  (with-redefs [http/post (fn [url] {:body "Goodbye world"})]
    (is (= {:body "Goodbye world"} (http/post "http://service.com/greet")))))

That's usually all you need.
You can of course use various Java mockup libraries, but I find I rarely need them.

Beware, `with-redefs` is not thread safe. If you run your tests concurrently you'll have crazy results :)
0 votes

Mocking function M is testing function A, which you assume calls function M, in the presence of a specially substituted function M?

But it's not super elegant to assume that A calls M. Instead, if A calls some feature that is substantial enough to merit mocking, pass M to A as an argument. (In other words, make the function that A calls, a parameter to A.) Make the feature overtly substitutable.

A sly, unobtrusive, flexible way to accomplish that is to use Stuart Sierra's "component", or apply a similar discipline, to connect up the program's facilities such as in your case the Internet. In effect, it accomplishes something akin to "dependency injection". Your test would inject a mock Internet, your operational mode would inject the real Internet.