silverdr
Troubles using Mox library for testing when no Mox expectations are defined
There is the Recaptcha library
https://github.com/samueljseay/recaptcha
which helps me in verifying recaptcha responses. All nice. Time for testing (yeah, after getting code to work somehow – apologies to all TDD fans). Obviously I don’t want to hit uncle google with my tests, so:
Mox.defmock(MyApplication.Accounts.MockRecaptcha, for: MyApplication.Accounts.RecaptchaBehaviour)
inside test_helper.ex. Needed to define that behaviour separately:
defmodule MyApplication.Accounts.RecaptchaBehaviour do
@callback verify(String.t(), Keyword.t()) :: {:ok, Response.t()} | {:error, [atom]}
@callback verify(String.t()) :: {:ok, Response.t()} | {:error, [atom]}
end
do some tests using:
MyApplication.Accounts.MockRecaptcha
|> expect(:verify, fn _response -> {:ok, _response} end)
So far so good, except… all other tests are now failing with:
** (Mox.UnexpectedCallError) no expectation defined for MyApplication.Accounts.MockRecaptcha.verify/1 in process #PID<0.854.0> with args [nil]
Reading the fine docs I find: “[…] you might want the implementation to fall back to a stub (or actual) implementation when no expectations are defined. stub_with/2 is just what you need!”
So another line in test_helper.ex:
Mox.stub_with(MyApplication.Accounts.MockRecaptcha, Recaptcha)
That doesn’t work because ** (ArgumentError) Recaptcha does not implement any behaviour, Well.. let’s add my own “proxy” then, which does:
defmodule MyApplication.Accounts.Recaptcha do
@behaviour MyApplication.Accounts.RecaptchaBehaviour
def verify(response, options \\ []) do
Recaptcha.verify(response, options)
end
end
And change the test_helper.ex line to
Mox.stub_with(MyApplication.Accounts.MockRecaptcha, MyApplication.Accounts.Recaptcha)
Now the ArgumentError is gone but all tests with no Mox expectations fail the same as before. No change with and without the stub_with/2.
And I feel like I spent already far too much time with it…
Any help to put me on track?
Most Liked
ruslandoga
I have a telegram bot client in my app which uses both mocks and stubs during tests and it seems to work fine. Here’s it’s setup:
config/test.exs
config :app, App.Bot, adapter: MockBot
lib/bot.ex
defmodule App.Bot do
# I'm using compile-time configuration
# https://hexdocs.pm/mox/Mox.html#module-compile-time-requirements
# it's probably not important
@adapter Application.compile_env!(:app, [__MODULE__, :adapter])
def set_webhook(url) do
@adapter.set_webhook(url)
end
# ...
end
lib/bot/adapter.ex
defmodule App.Bot.Adapter do
@moduledoc false
@callback set_webhook(url :: String.t()) :: :ok | {:error, map}
# ...
end
test/support/mocks.exs
Mox.defmock(MockBot, for: App.Bot.Adapter)
test/support/stub_bot.ex
defmodule StubBot do
@behaviour App.Bot.Adapter
@impl true
def set_webhook(_url), do: :ok
# ...
end
and finally test/support/data_case.ex and other helper cases for tests that end up touching the bot module have Mox.stub_with/2 in setup:
defmodule App.DataCase do
use ExUnit.CaseTemplate
# ...
setup tags do
# ...
Mox.stub_with(MockBot, StubBot)
# ...
end
end
silverdr
Right - if I put the stub_with into both conn_case and data_case then all tests work normally. IOW – @ruslandoga – you’re my saviour, man! I guess it has to be invoked always in the given test file context. If I now re-read the doc, the wording might actually imply this… gosh!
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
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









