Hi! Thank you for this excellent library! I have a small problem. In the code below, the first expect that refers to @services-proxy executes after all tests, regardless of the sleep times I put in.
(ns rama.core-module-test
(:require
[hashp.preload]
[rama.core-module :as sut]
[shared.schema :as schema]
[com.rpl.rama :as r]
[com.rpl.rama.path :as rp]
[com.rpl.rama.test :as rtest]
[lazytest.core :as lt :refer [defdescribe describe expect it expect-it]]))
(defdescribe core-module-test
(describe "service"
(schema/init-registry)
(with-open [ipc (rtest/create-ipc)]
(rtest/launch-module! ipc sut/CoreModule {:tasks 4 :threads 4})
(let [module-name (r/get-module-name sut/CoreModule)
service-depot (r/foreign-depot ipc module-name "*service-depot")
services (r/foreign-pstate ipc module-name "$$services")
services-proxy (r/foreign-proxy [] services)]
(let [new-service (schema/->CreateService "mow-lawn" "mow lawn" "" "lawn-care" "per-sqft" true)
{id "core"} (r/foreign-append! service-depot new-service)
_ (Thread/sleep 50)
result (r/foreign-select-one [] services)]
(it "should create a service"
(expect
(= {id {:id id
:name "mow lawn"
:description ""
:category "lawn-care"
:price-units "per-sqft"
:active? true
:deleted? false}} result))
(expect
(= {id {:id id
:name "mow lawn"
:description ""
:category "lawn-care"
:price-units "per-sqft"
:active? true
:deleted? false}} @services-proxy))))
(let [updated-service (schema/->UpdateService
"mow-lawn"
[(schema/->ServiceEdit :description "foo bar baz")])
{id "core"} (r/foreign-append! service-depot updated-service)
_ (Thread/sleep 50)
result (r/foreign-select-one [] services)]
(it "should update a service"
(expect
(= {id {:id id
:name "mow lawn"
:description "foo bar baz"
:category "lawn-care"
:price-units "per-sqft"
:active? true
:deleted? false}} result))
(expect
(= {id {:id id
:name "mow lawn"
:description "foo bar baz"
:category "lawn-care"
:price-units "per-sqft"
:active? true
:deleted? false}} @services-proxy))))))))
(This refers to Rama code).I've pushed some changes to a branch, let me know if you think these two sections are more clear about the differences. https://github.com/NoahTheDuke/lazytest/tree/nb/push-nyzlkooxrnqm?tab=readme-ov-file#writing-tests-with-lazytest https://github.com/NoahTheDuke/lazytest/tree/nb/push-nyzlkooxrnqm?tab=readme-ov-file#common-patterns
The side-by-side comparison with clojure.test is awesome -- thank you!
glad that helped. i feel like there are better examples but they start to get unwieldy when they grow too big lol
Thank you! that's great. it is written very clearly and helped me a lot
i merged that branch to main
I appreciate it. Documentation is hard.
I suspect you're falling foul of a common misunderstanding about LazyTest: when that defdescribe executes, it produces a function -- a test suite -- that is later executed by the runner, so everything "between" the describe and the it has already executed when the test suite is created, and then the it / expect parts run:
user=> (defdescribe foo
#_=> (println "one")
#_=> (describe "outer stuff"
#_=> (println "two")
#_=> (it "inner stuff"
#_=> (println "three")
#_=> (expect (nil? (println "four")))
#_=> (println "five"))
#_=> (println "six"))
#_=> (println "seven"))
#'user/foo
user=> (run-test-var #'foo)
one
two
six
seven
three
four
five
Ran 1 test cases in 0.00069 seconds.
0 failures.
{:total 1, :pass 1, :fail 0}
See how one, two, six, seven are all printed before three, four, five?and:
user=> (foo)
one
two
six
seven
#lazytest.suite.Suite{:type :lazytest/var, :doc "foo", :children [#lazytest.suite.Suite{:type :lazytest/suite, :doc "outer stuff", :children [#lazytest.test_case.TestCase{:type :lazytest/test-case, :doc "inner stuff", :body #function[user/foo-20716--20717/fn--20718/fn--20723/it--19991--auto----20728], :context {}, :ns #namespace[user], :file "NO_SOURCE_PATH", :line 5, :metadata nil, :column 13}], :context {}, :ns #namespace[user], :file "NO_SOURCE_PATH", :line 3, :var nil, :metadata nil, :column 3}], :context {}, :ns #namespace[user], :file "NO_SOURCE_PATH", :line nil, :var nil, :metadata {:var #'user/foo}}Ah. Thank you very much @seancorfield!
I think this catches everyone out at least once or twice 🙂
@nbtheduke Is there a GH issue open about adding an example like this to the docs, to show how best to set up this sort of side-effect based testing?
Ah, it was this issue and it is closed: https://github.com/NoahTheDuke/lazytest/issues/24 @hadilsabbagh18 I guess the addition Noah added to the README to address #24 still needs further elaboration to clarify the behavior?
yeah, seems i need to be way more explicit about this. if you have any suggestions or a PR even, i'm all for it
I'm running into the exact same issue: the resource created by with open is already closed by the time the test runs. I'm curious: does lazytest only handle this using dynamic variables and binding to manage the resource? I find that approach a bit tedious.
atoms, volatiles, dynamic variables
the behavior and style are based on existing test frameworks in other languages with mutable variables such as javascript, ruby, python etc
He's talking about describe vs it and when it runs
right, i got that. the idea is that you only do set up/tear down in context functions or within test cases (it blocks)
More examples in the readme would help:grinning:
i'll spend some time on it tomorrow
Thanks! This is very helpful!