xgeek116
I’m using using mox to help me with my unit testing (for now, I want to mock a function that fetches external API).
my mix.exs :
{:mox, "~> 1.0", only: :test}
My test_helper.exs :
ExUnit.start()
Mox.defmock(MyApp.MockExternalSources, for: MyApp.MyModule.ExternalSources)
My module code (MyApp.MyModule.ExternalSources) :
defmodule MyApp.MyModule.ExternalSources do
@callback http_get_resource(url :: String.t(), headers :: list()) :: {:ok, map()} | :error
@callback fetch_one_external_resource(params :: map()) :: map()
require Logger
def fetch_one_external_resource(params) do
with {:ok, data} <-
http_get_resource(params["url"], params["headers"]) do
do_something(data)
else
:error -> %{}
end
end
def http_get_resource(url, headers) do
case HTTPoison.get(url, headers) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
{:ok, Poison.decode!(body)}
{:ok, %HTTPoison.Response{status_code: 404}} ->
:error
{:error, %HTTPoison.Error{reason: _reason}} ->
:error
end
end
end
And my test module :
defmodule MyApp.MyModule.ExternalSources.Test do
use ExUnit.Case, async: true
import Mox
setup :verify_on_exit!
test "fetch and process external data" do
MyApp.MockExternalSources
|> expect(:http_get_resource, fn _url, _headers ->
{:ok, %{status_code: 200, body: %{key1: "value1", key2: "value2"}}}
end)
params = %{
"url" => "xxx",
"headers" => "yyy"
}
assert MyApp.MyModule.ExternalSources.fetch_one_external_resource(params) ==
%{"new_key1" => "value1", "new_key2" => "value2"}
end
end
But I always get a failed assertion and the behaviour is that the right value (MyApp.MyModule.ExternalSources.fetch_one_external_resource(params)) is actually calling the external API and getting the real values ignoring my static data in the mock (%{key1: "value1", key2: "value2"})
Any help please !
Trending in Questions
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
Hello,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
Hi everyone,
I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding.
I sta...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted”
Version...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
hubertlepicki
Did you clear / trigger application rebuilt after introducing the Mox mock? I think I was having similar problem and I had to trigger application recompilation, by either
mix clearor even removing the whole _build dir and rebuilding it from scratch.xgeek116
Hi @hubertlepicki , yes I did but the same result.
I think there is something missing (an implementation or something ?) to detect the mocked function
karlosmid
Hi!
You are missing env variables.
In
test_helpersyou need to putApplication.put_env(:app_name, :external, MyApp.MockExternalSources)and in test you need to call it in this way:
Application.get_env(:app_name, :external).fetch_one_external_resourceand mock in test
fetch_one_external_resourcefunction instead ofhttp_get_resource.I suggest that you refactor your
MyApp.MyModule.ExternalSourcesso thathttp_get_resourcemethods is implemented in new module.This way you separate your business logic from contacting external resources.
xgeek116
Hi @karlosmid ,
I have this error :
** (Mox.UnexpectedCallError) no expectation defined for MyApp.MockExternalSources.fetch_one_external_resource/1 in process #PID<0.529.0> with argsMaybe I didn’t get it right, can you please help me add your proposition to my code ?
crova
Mox was expecting
fetch_one_external_resource/1as the name of the function to be called, but your expectation is calling another function.xgeek116
Yes because I mocked the
http_get_resource/2which does the HTTP call, I just need to simulate that behaviour not the entirefetch_one_external_resource/1functionCan anyone please show me what’s wrong ?
Here is the updates that I did based on @karlosmid answer.
in test_helper.ex :
I added ;
Application.put_env(:app_name, :external, MyApp.MockExternalSources)in my test file I updated the assert to :
xgeek116
If I mock
fetch_one_external_resourcethere will not be a real test, It will be a static verification of the resulttrisolaran
The core problem is that it’s not enough to create a mock from a behaviour, you should also tell your implementation to use it in tests. Right now, your
fetch_one_external_resourceis always callinghttp_get_resource. The implementation is fixed.As others have already pointed out:
http_get_resourceinto its own module. Let’s call it “APIClient”ExternalSourcesretrieve whichAPIClientmodule to use vie config. By default it would beAPIClient, in the test environment it will beAPIClientMockAPIClientMockin thests withdefmockand set the desired expectations in your testdorgan
Or you could just use Patch
xgeek116
@trisolaran , here is all the updates that I did by I always get an empty left in assertion (
left: %{})In ExternalSources module, I added :
@api_client Application.compile_env!(:app_name, :api_client)The call to the http_get_resource became :
@api_client.http_get_resource(url, headers)In test_helper.exs I deleted the lines :
Mox.defmock(MyApp.MockExternalSources, for: MyApp.MyModule.ExternalSources)and
Application.put_env(:app_name, :external, MyApp.MockExternalSources)In my test file, I added :
In my config.exs :
config :app_name, api_client: MyApp.MyModule.APIClientIn my test.exs :
config :app_name, api_client: MyApp.MyModule.APIClientMock