bian2510
** (Mox.VerificationError) error while verifying mocks for #PID<0.534.0>: * expected DirectHomeApi.Aws.MockS3.upload_files/1 to be invoked once but it was invoked 0 times
Hello guys I’m trying mock a function that is executed when I call my endpoint (In the middle of all code).
But when I call my endpoint all is working but th mock not is called and upload the file to s3. Can someone give me a help with this?
Thanks! ![]()
This is the error
1) test upload user image when the user is logged (DirectHomeApiWeb.UserControllerTest)
test/direct_home_api_web/controllers/user_controller_test.exs:165
** (Mox.VerificationError) error while verifying mocks for #PID<0.534.0>:
* expected DirectHomeApi.Aws.MockS3.upload_files/1 to be invoked once but it was invoked 0 times
stacktrace:
(mox 1.0.0) lib/mox.ex:692: Mox.verify_mock_or_all!/3
(ex_unit 1.11.3) lib/ex_unit/on_exit_handler.ex:143: ExUnit.OnExitHandler.exec_callback/1
(ex_unit 1.11.3) lib/ex_unit/on_exit_handler.ex:129: ExUnit.OnExitHandler.on_exit_runner_loop/0
user_controller_test.ex
defmodule DirectHomeApiWeb.UserControllerTest do
use DirectHomeApiWeb.ConnCase
use ExUnit.Case, async: true
import Mox
alias DirectHomeApi.Model.User
alias DirectHomeApi.Repo
doctest DirectHomeApi.Aws.S3
setup :verify_on_exit!
describe "upload user image" do
test "when the user is logged", %{conn: conn} do
DirectHomeApi.Aws.MockS3
|> expect(:upload_files, fn _image -> {:ok, %{}} end)
image = %Plug.Upload{
content_type: "image/jpeg",
filename: "test.jpeg",
path: "test/images/some_image.jpeg"
}
user = create_user()
conn =
sigin_and_put_token(conn, user)
|> post(Routes.user_path(conn, :upload_image), %{"id" => user.id, "photo" => image})
assert 200 = conn.status
assert {:ok, %{"sucess" => "The image could be saved sucessfully"}} = Jason.decode(conn.resp_body)
#%{"error" => "The image not could be storage in s3"}
end
end
end
s3.ex
defmodule DirectHomeApi.Aws.S3 do
@callback upload_files(arg :: any) :: {:ok, map()} | {:ok, map()}
def upload_files(image) do
content_type = image.content_type
format_file = String.split(content_type, "/") |> List.last()
file_name = "#{Ecto.UUID.generate()}.#{format_file}"
file_path = image.path
bucket = System.get_env("BUCKET_NAME")
ExAws.S3.put_object(bucket, file_name, File.read!(file_path), [
{:content_type, content_type}
])
|> ExAws.request()
|> case do
{:ok, _} -> {:ok, file_name}
{:error, error} -> {:error, error}
end
end
end
test_helper.ex
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(DirectHomeApi.Repo, :manual)
Mox.defmock(DirectHomeApi.Aws.MockS3, for: DirectHomeApi.Aws.S3)
Marked As Solved
edisonywh
That’s what yukster pointed out, you are not swapping out the implementation in your user.ex.
The error message is telling you exactly that:
expected DirectHomeApi.Aws.MockS3.upload_files/1 to be invoked once but it was invoked 0 times
In your code you never made a call to MockS3.
You have a line like this:
def update_image(id, user_image) do
S3.upload_files(user_image["photo"])
...
You see how it directly calls S3? You need to inject the dependency here, so something like this instead:
def update_image(id, user_image) do
s3_provider().upload_files(user_image["photo"])
...
end
def s3_provider, do: Application.fetch_env!(:your_app, :s3_provider)
In your config you would need to have s3_provider be configured to the real S3 omdule, and in your test you would need to configure it to use your MockS3.
This line:
Mox.defmock(DirectHomeApi.Aws.MockS3, for: DirectHomeApi.Aws.S3)
This creates a mock for you based on the behaviour, but you still need to inject the dependency yourself
Also Liked
karlosmid
Mock reported that mocked function was not called.
From this code, it seems that you are calling the wrong controller. Do you have controller with function named upload_image? Try to replace upload_image with upload_files
yukster
Also you don’t show the controller code… The code that calls S3.upload_files. Are you swapping out the real module for the mock? Defining the mock is only half the solution. You need to also set up test.exs to put the mock in the env and make the controller get the S3 module from the application env instead of using the module directly. Hope that helps!
yukster
Thanks, @edisonywh! Yep, that’s exactly what I was getting at (but was replying on a tablet in the middle of the night with insomnia, so I didn’t give examples). Thank you for the explicit instructions.
I think the official docs could be better about this: Mox — Mox v1.2.0. It talks about putting the module being mocked into the app config but the example of using a mock doesn’t take that approach.
Basically, there’s no magic involved. Just defining a mock doesn’t make it be used. You have to make the real code use the real module and the test code use the mock.
Their example also uses it more like a stub, just returning a value, not pattern matching the args, and not asserting anything about how the mock was called. If I’m going to use expect then I like to assert something in the function body passed to it. Or at the very least, pattern match the params so that the test will fail if the mock isn’t called the right way.
Anyway, @bian2510 I hope all this helps and doesn’t confuse you even more. I definitely struggled a bit with Mox when I first adopted it. And it still bothers me some that I have to alter the production code in order to use a Mox mock. But that alteration is limited to just making a given module configurable via the application env so it’s worth it.
Last Post!
bian2510
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
- #forms
- #api
- #metaprogramming
- #security
- #hex









