# Inline tests, do you do it?

**URL:** https://clojureverse.org/t/inline-tests-do-you-do-it/4083
**Category:** Watercooler
**Tags:** testing
**Created:** [March 31, 2019, 10:34am UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083 "2019-03-31T10:34:13Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![PEZ](https://clojureverse.org/user_avatar/clojureverse.org/pez/32/1187_2.png) [@PEZ](https://clojureverse.org/u/PEZ)
#### Post date: [March 31, 2019, 10:34am UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/1 "2019-03-31T10:34:13Z")

</div>

When my project allows it, I like to use the `attrs-map` of functions to inline my tests. Seeing that [not even @danielcompton seems to be aware of this feature](https://github.com/danielcompton/defn-spec#limitations), I thought I might tip about it here.

The thing is that the Clojure test runner looks for `:test` in the `attrs-map` of defined functions and runs them. Here’s a super simple example:

```clojure
(defn abs
  "The absolute value of a number."
   {:test (fn []
            (is (= (Math/abs 5) 5))
            (is (= (Math/abs -2) 2))
            (is (= (Math/abs 0) 0)))}
  [x]
  {:pre [(number? x)]}
  (if (pos? x)
    x
    (- x)))

```

I think this has lots of advantages. Keeping the (or at least, some) tests with the software under test makes for good documentation, promotes keeping the tests updated and is generally convenient.

With Clojure it gets extra powerful since you can use the REPL to grow the tests and the code you are testing without having to open some other file or window. I sometimes find myself entering a flow where I sort of mix REPL and test driven development. So instead of doing my experiments in the REPL window or even in a `comment` block I carry them out in that `attrs-map`, and then some of the experiments can just stay as tests.

It might not be for everyone, or for every occasion, but I recommend giving it a try. You might like it! 😄

EDIT. In the original post I said this doesn’t work in ClojureScript. It does. See below. (I don’t know why it didn’t work when I tried this some while ago. It certainly wasn’t for lack of trying…)

---

<div class="post-metadata">

### Author: ![thheller](https://clojureverse.org/user_avatar/clojureverse.org/thheller/32/534_2.png) [@thheller](https://clojureverse.org/u/thheller)
#### Post date: [March 31, 2019, 12:15pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/2 "2019-03-31T12:15:15Z")

</div>

> [@PEZ](#):
>
> A huge drawback is that the ClojureScript test runner does not discover these tests.

It does?

FWIW I never do this and wouldn’t recommend doing it either.

When I write test I keep them separate since quite often the tests will become longer than the actual implementation, as your example already shows. Oftentimes the “tests” will require additional dependencies which would polute the original `ns` if done inline.

---

<div class="post-metadata">

### Author: ![PEZ](https://clojureverse.org/user_avatar/clojureverse.org/pez/32/1187_2.png) [@PEZ](https://clojureverse.org/u/PEZ)
#### Post date: [March 31, 2019, 12:33pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/3 "2019-03-31T12:33:25Z")

</div>

> [@thheller](#):
>
> It does?

It doesn’t.

> [@PEZ](#):
>
> Keeping the (or at least, some) tests with the software under test

> [@thheller](#):
>
> quite often the tests will become longer than the actual implementation

Yeah, the ratio of test code/tested code is often \> 1. I don’t see it as problematic, though.

> [@thheller](#):
>
> Oftentimes the “tests” will require additional dependencies which would polute the original `ns` if done inline.

This certainly happens, and when it does I often move those tests out to a test namespace. It’s one of those reasons why ”_(or at least, some)_ tests”. I also know of people who have written large and successful apps without worrying about the extra dependencies in the tested namespace.

---

<div class="post-metadata">

### Author: ![thheller](https://clojureverse.org/user_avatar/clojureverse.org/thheller/32/534_2.png) [@thheller](https://clojureverse.org/u/thheller)
#### Post date: [March 31, 2019, 12:36pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/4 "2019-03-31T12:36:58Z")

</div>

> [@PEZ](#):
>
> It doesn’t.

```auto
[1:1]~cljs.user=> (require '[cljs.test :as t])
nil
[1:1]~cljs.user=> (defn foo {:test (fn [] (t/is (= 1 2)))} [])
#object[Function]
[1:1]~cljs.user=> (t/run-tests)

Testing cljs.user

FAIL in (foo) (at C:475:6)
expected: (= 1 2)
  actual: (not (= 1 2))

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
nil

```

---

<div class="post-metadata">

### Author: ![PEZ](https://clojureverse.org/user_avatar/clojureverse.org/pez/32/1187_2.png) [@PEZ](https://clojureverse.org/u/PEZ)
#### Post date: [March 31, 2019, 12:39pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/5 "2019-03-31T12:39:23Z")

</div>

Wow, now I must go see why this hasn’t worked for me. There’s hope, thanks!

---

<div class="post-metadata">

### Author: ![Phill](https://clojureverse.org/letter_avatar_proxy/v4/letter/p/779978/32.png) [@Phill](https://clojureverse.org/u/Phill)
#### Post date: [March 31, 2019, 12:58pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/6 "2019-03-31T12:58:41Z")

</div>

Hmm, in [cljs/cljs/test.cljs](https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/test.cljs) I see this:

```
(defn test-var
  "If v has a function in its :test metadata, calls that function,
  add v to :testing-vars property of env."
  [v]
(run-block (test-var-block v)))

```

But I’m not sure how it’s hooked up. Have you put a note into [https://dev.clojure.org/jira/](https://dev.clojure.org/jira/)?  
(Or [https://clojurescript.org/about/differences](https://clojurescript.org/about/differences) if it will remain a “difference from Clojure”?)

---

<div class="post-metadata">

### Author: ![PEZ](https://clojureverse.org/user_avatar/clojureverse.org/pez/32/1187_2.png) [@PEZ](https://clojureverse.org/u/PEZ)
#### Post date: [March 31, 2019, 12:59pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/7 "2019-03-31T12:59:55Z")

</div>

Wow, again. I can’t reproduce the problem I had. Super, duper nice! Will start inlining a lot of tests now.

---

<div class="post-metadata">

### Author: ![PEZ](https://clojureverse.org/user_avatar/clojureverse.org/pez/32/1187_2.png) [@PEZ](https://clojureverse.org/u/PEZ)
#### Post date: [March 31, 2019, 1:04pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/8 "2019-03-31T13:04:32Z")

</div>

Thanks. I have edited the post about this. It doesn’t seem to be a problem, as @thheller shows above. I am very confused now, but also happy.

---

<div class="post-metadata">

### Author: ![didibus](https://clojureverse.org/user_avatar/clojureverse.org/didibus/32/951_2.png) [@didibus](https://clojureverse.org/u/didibus)
#### Post date: [March 31, 2019, 4:28pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/9 "2019-03-31T16:28:43Z")

</div>

You can also use [https://clojuredocs.org/clojure.test/with-test](https://clojuredocs.org/clojure.test/with-test)

---

<div class="post-metadata">

### Author: ![thheller](https://clojureverse.org/user_avatar/clojureverse.org/thheller/32/534_2.png) [@thheller](https://clojureverse.org/u/thheller)
#### Post date: [March 31, 2019, 4:40pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/10 "2019-03-31T16:40:01Z")

</div>

@PEZ if you tested this on older versions of shadow-cljs it might indeed not have worked. I changed it a little while ago, so previously it did indeed not account for `:test` metadata.

---

<div class="post-metadata">

### Author: ![PEZ](https://clojureverse.org/user_avatar/clojureverse.org/pez/32/1187_2.png) [@PEZ](https://clojureverse.org/u/PEZ)
#### Post date: [March 31, 2019, 7:15pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/11 "2019-03-31T19:15:58Z")

</div>

Phew! I was really beginning to wonder. 🤠

---

<div class="post-metadata">

### Author: ![teodorlu](https://clojureverse.org/user_avatar/clojureverse.org/teodorlu/32/2896_2.png) [@teodorlu](https://clojureverse.org/u/teodorlu)
#### Post date: [March 31, 2019, 9:17pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/12 "2019-03-31T21:17:57Z")

</div>

I do something like this all the time! Not exactly inline tests, but I like keeping the test code in the same block when I’m developing.

```clojure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Step 1
;;
;; I like to be able to C-c C-c on the block to see where
;; I'm at. So I evolve the function definition and the test
;; in sync.

(do
  (defn three []
    (+ 1 1))
  [(three)
   (= (three) 3)]
  )
;; => [2 false]

;; Not right -- work on it till it makes sense.

(do
  (defn three []
    (+ 1 1 1))
  [(three)
   (= (three) 3)]
  )
;; => [3 true]

;; there!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Step 2a
;;
;; Small functions. Document the function interface with an
;; example in the docstring.

(defn three
  "Produce the number three

  (three)
  ;; => 3
  "
  []
  (+ 1 1 1))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Step 2b
;;
;; Larger functions. Make a proper test!

;; math.clj
(defn three
  "Produce the number three"
  []
  (+ 1 1 1))

;; math_test.clj
(deftest test-three
  (is (= 3 (three))))

```

---

<div class="post-metadata">

### Author: ![jwr](https://clojureverse.org/user_avatar/clojureverse.org/jwr/32/685_2.png) [@jwr](https://clojureverse.org/u/jwr)
#### Post date: [April 1, 2019, 4:04pm UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/13 "2019-04-01T16:04:24Z")

</div>

> [@thheller](#):
>
> When I write test I keep them separate since quite often the tests will become longer than the actual implementation, as your example already shows. Oftentimes the “tests” will require additional dependencies which would polute the original `ns` if done inline.

As a counterpoint, I keep my tests with the code, usually in a `deftest` form right after the function. Main reasons:

- They serve as documentation and a demonstration, showing behavior in corner cases (nils, empty collections, etc)
- Tests which live in a separate file structure tend to get rusty over time

As to dependencies, since I only write unit tests, there are no dependencies.

I’m not saying this is the One True Way, I just wanted to point out that separating tests from code is not necessarily the One True Way either. There are many approaches to writing tests.

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [October 1, 2019, 4:15am UTC](https://clojureverse.org/t/inline-tests-do-you-do-it/4083/14 "2019-10-01T04:15:11Z")

</div>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.
