arnomi
Assert condition with timeout
In my test suite I occasionally find myself needing to work with timeouts if some processing is done asynchronously. In this case I often resort to
:timer.sleep(100)
assert condition
Is there a way to instead specify an assertion that takes a condition and a timeout with the following logic: If the condition holds before the timeout is up then the test passes. Otherwise it fails. If that assertion would not simply implement the above but check regularly, say every ms, then this would allow for
- a more robust test suite as the timeout can be put to a much larger value than the above sleep workaround
- for a much faster test suite, since the full sleep is usally superfluous.
Implementing this functionality with a macro should be (I guess) straight forward. If so, are there by any chance already any libraries that offer this type of assertion or if not, is the above an anti-pattern that should be avoided?
Most Liked
peerreynders
assert_receive/3 has already been pointed out to you - have a look at it and it’s friends.
- “Busy wait” is the anti-pattern - it doesn’t matter if the wait is 100 or 1 ms.
- In an efficient system events worth observing need to be broadcast - not “watched”. Interested parties should be able to register (and unregister) their “interest” so that they can be notified when the event occurs. That notification (event message) can then be used with
assert_receive/3.
The fact that you need to structure a test in a “busy wait” manner may suggest that you have a design issue.
What is that ETS table used for? Typically they exist to support some sort of request served by the process. If the same process sends the async insert followed by a synchronous request then the request should be served after the insert has been processed - so the result of the request should be consistent with the insert being successful.
peerreynders
This is no different than logging. Write your ETS access functions in such a way that for testing they compile to send a digest message to a named process for testing. When compiling for production that code can then be safely omitted.
elixir/lib/logger/lib/logger.ex at v1.5.3 · elixir-lang/elixir · GitHub
Last Post!
alexandre
Just another idea, following @josevalim rationally and with no external dependencies. Code isn’t readable since Erlang trace API is complicated. But if you abstract the complication away in test helper functions, it can become manageable…
pattern = {Module, :function, 0} # it can be any {mod, fun, arity}
:erlang.trace_pattern(pattern, [{:_, [], [{:return_trace}]}])
:erlang.trace(:all, true, [:call])
# do async work that ends up calling Module.function()
assert_receive {:trace, _pid, :return_from, ^pattern, {:noreply, _state}} # block until Module.function is called
# write the rest of your assertions here, the ones that need `Module.function` to be returned...
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









