Fork me on GitHub
#testing
<
2021-08-02
>
West03:08:10

Hey guys, so I’m attempting to build a web server purely using Clojure libraries. Now there’s a twist. I’m doing it in a strictly test-driven, way. Now I want to write the simplest test I can to show that a server exists. Should I make a get request? Or something simpler?

Russell Mull04:08:31

Answering in two parts: 1. The most direct way I can think of to see if a server exists is to try and open up a socket to that port. 2. While it's an interesting exercise, I suspect your time will be better spent testing things farther up the stack. This is essentially testing the web server itself, which has probably already received a lot of attention by many people.

West04:08:21

You’re definitely right that testing to make sure a server exists is pretty trivial.

West04:08:21

Now a follow up question. How should I configure my test suite to make sure my server is running on each test run. I’m probably gonna use httpkit, so would I just call run-server from my test file?

Russell Mull04:08:09

If you really want end-to-end tests, then yes. use-fixtures can help structure this code, if you feel it's repetetive: https://clojuredocs.org/clojure.test/use-fixtures. That said, it's common to structure clojure code such that most of the pieces are purely functional, and can be tested independent of any kind of fixture situation. For example, you'll probably have request handlers that are little more than a function. Most testing can be done on that function directly. Of course the integration tests should still exist, but people usually don't write as many of those.

West04:08:29

Well thank you for your help, and thank you for introducing me to use-fixtures! That’s a really big help for me.

jumar17:08:13

For basic smoke test I recommend adding a simple route like /status that would return pkain text “ok” on GET

dorab16:08:42

If you do end up using fixtures, the following link might be helpful. https://stuartsierra.com/2016/05/19/fixtures-as-caches

Proctor13:08:39

question on the testing macro. The docstring states: > Adds a new string to the list of testing contexts. May be nested, > but must occur inside a test function (deftest). but a co-worker put it outside a group of deftests and said it works e.g.

(testing "desc"
  (deftest "case1"
    (testing "this tests x" ...))
  (deftest "case2"
    (testing "y holds as well" ...)))
I went looking at the source (in CLJS), and it doesn’t seem like it has to be in a deftest since testing updates the :testing-contexts in the current-env (https://github.com/clojure/clojurescript/blob/r1.10.866/src/main/cljs/cljs/test.cljc#L216-L225) Just trying to get an understanding if this is really safe or coincidentally safe; does anybody have experience with this?

mauricio.szabo15:08:31

A deftest inside a testing seems quite weird. It can also complicate a little bit on async tests in ClojureScript, so I would recommend against it

mauricio.szabo15:08:16

Also, testing updates the :testing-contexts but inside a dynamic var. What it means, in practice, is the following (using your first example):

; Here, it'll update the testing context to ["desc"]
(testing "desc"
  (deftest "case1"
     ; Here, it'll update the testing context to ["desc" "this texts x"]
    (testing "this tests x" 
      ...
    ) ; Here, it'll be back to ["desc"]
  )
) ; And here, to []

mauricio.szabo16:08:21

As the testing-context is a global, dynamic var, this "binding-rebinding" will work *if* (and that's a big IF) ClojureScript loads the file AND run the tests at the same time. Most of the time, that's not the case, so what it'll happen is something like this:

; Here, it'll update the testing context to ["desc"]
(testing "desc"
  (deftest case1 ; Here, it'll just define the var
    (testing "this tests x" ... )
  )
); Back to []
When it's time to run the test, your testing context is empty, so you won't see "desc this tests x". So, officially, the first testing serves no purpose on this example.

Proctor16:08:49

I think they just wrote that for reading context, and wrapping a let that covers the deftest with shared context

Proctor16:08:47

it was agreed to back it out, but it piqued my curiosity enough that I wanted to get a deeper understanding. 😉

mauricio.szabo16:08:13

Kinda, but the testing description appears when a test fails also

mauricio.szabo16:08:32

For example:

user=> (deftest sum-numbers (testing "1+2" (testing "must be 3" (is (= 2 (+ 1 2))))))
#'user/sum-numbers
user=> (run-tests)

Testing user

FAIL in (sum-numbers) (NO_SOURCE_FILE:1)
1+2 must be 3
expected: (= 2 (+ 1 2))
  actual: (not (= 2 3))

Proctor16:08:23

yeah, again I am not sure if they did that for extra description context, or more the idea of wrapping a let block

mauricio.szabo16:08:15

I think they did, otherwise I see no value on adding that :testing-contexts element

Proctor16:08:01

they were able to run it they said; but the docstring said inside deftest only, so felt like it would be a loophole that might be able to be exploited, but didn’t feel like we should be counting on it…

mauricio.szabo16:08:03

If you look at git blame, it seems it was intentional

mauricio.szabo16:08:36

It's inside deftest because otherwise the description will not be added to failures

Noah Bogart13:08:57

looks like it expects that the *current-env* dynvar is specified here

Noah Bogart13:08:56

so it looks like it “works” if you’ve imported/required clojure.test, but probably not otherwise

Proctor13:08:00

I was reading something similar… wasn’t sure if anybody had experience with it. 😉

Noah Bogart13:08:23

ah, thought you couldn’t find the definition, my apologies.

Proctor13:08:57

also new to production support Clojure/ClojureScript vs just doing personal abandonware to solve problems; so part of it is a question on how safe it it to depend on the implementation… I know Clojure is stable, wasn’t sure if this is one of those that is implementation stable, vs keep to the contract in the Docstrings, specs, etc. stable. 😉