Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Clojure: Expectations Verify Interaction Args

DZone's Guide to

Clojure: Expectations Verify Interaction Args

· Java Zone
Free Resource

Try Okta to add social login, MFA, and OpenID Connect support to your Java app in minutes. Create a free developer account today and never build auth again.

The expectations framework provides the ability to create interaction (or behavior) based tests. I've previously written about adding interaction based testing to expectations; however, the examples from that blog entry focused exclusively on testing interactions where each argument is matched using equality. In this entry I'll give examples of how each argument can be also be verified using a class, regex, exception, or a custom function.

When writing state based tests using expectations the type of test you're writing is inferred from the expected value. If the expected value is a regex, expectations will test the actual value to see if it matches the regex. If you passed in a class, expectations will test the actual value to see if it's an instance of that class. If you passed in an exception... you get the idea. All of what I said above, is also true for arguments of an interaction.

Let's start with a simple interaction based test:

(ns blog-expectations

(:use expectations))

 

(expect (interaction (spit "/tmp/hello-world" "some data" :append true))

(do

(spit "/tmp/somewhere-else" "nil")

(spit "/tmp/hello-world" "some data" :append true)))

In the example above, we're calling the spit function with exactly the arguments that we've specified in our test. This test will pass; however, we've had to specify the exact file location and the exact data. If for some reason you can't specify exactly what the argument will be, it's nice to have a way to specify as much as you possibly can.

In the example below, we're still specifying the exact data, but we're only verifying that the file is somewhere in /tmp/.

(expect (interaction (spit #"/tmp/" "some data" :append true))

(do

(spit "/tmp/somewhere-else" "nil")

(spit "/tmp/hello-world" "some data" :append true)))

As I previously mentioned, we can also get more general and only verify the class of an argument. For example, if we knew our data was going to be a String, but we didn't want to specify exactly what that string was, the following test would do the trick.

(expect (interaction (spit #"/tmp/" String :append true))

(do

(spit "/tmp/somewhere-else" "nil")

(spit "/tmp/hello-world" "some data" :append true)))

While expectations provides you with a lot of default options, there are times when you'll want to write your own argument "matcher". As a contrived example, let's pretend that we want to test that the last argument is true or nil.

(defn true-or-nil? [x]

(or (true? x) (nil? x)))

 

;; this test passes

(expect (interaction (spit #"/tmp/" String :append true-or-nil?))

(do

(spit "/tmp/somewhere-else" "nil")

(spit "/tmp/hello-world" "some data" :append true)))

 

;; so does this test

(expect (interaction (spit #"/tmp/" String :append true-or-nil?))

(do

(spit "/tmp/somewhere-else" "nil")

(spit "/tmp/hello-world" "some data" :append nil)))

 

;; this test fails

(expect (interaction (spit #"/tmp/" String :append true-or-nil?))

(do

(spit "/tmp/somewhere-else" "nil")

(spit "/tmp/hello-world" "some data" :append "not true or nil")))

One of the best features of expectations is it's error reporting, and the same error reporting logic is applied to arguments when an interaction based test fails. Given the example above, you'll get the following error message.

failure in (success_examples.clj:204) : success.success-examples
           expected: (spit #"/tmp/" String :append true-or-nil?) 
                got: 0 times 

           -- got: (spit "/tmp/somewhere-else" "nil")
           "nil", "/tmp/somewhere-else" are in actual, but not in expected
           true_or_nil_QMARK, #"/tmp/", :append, String are in expected, but not in actual
           expected is larger than actual 

           -- got: (spit "/tmp/hello-world" "some data" :append "s")
           - arg4: not true or nil

As you can see both calls are reported, and each argument has a detailed report (if it did not match).

Finally, expectations provides and additional function that can be used to verify that certain key/value pairs are in an argument. The following example doesn't really make sense, since you'd never want to pass a map as the last argument to spit, but it's easy to follow in the context of this blog entry.

(expect (interaction (spit String #"some da" keyword? (contains-kvs :a :b :c :d)))

(spit "/tmp/hello-world" "some data" :append {:a :b :c :d :e :f}))

In the above example, (contains-kvs) is used to verify that the final argument to spit contains the key/value pairs :a :b :c :d.

I hope that interaction arg matching follows the principle of least surprise, since it behaves the same as expectations state based tests. I also hope that the ability to use an arbitrary function for verification will provide any necessary flexibility. If you're using expectations, give it a try and let me know.






 

Build and launch faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:

Published at DZone with permission of Jay Fields, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}