edgurgel / mimic

A mocking library for Elixir
https://hexdocs.pm/mimic
Apache License 2.0
405 stars 33 forks source link

Question: arguments pattern matching. #50

Open xantrac opened 1 year ago

xantrac commented 1 year ago

Is the Mimic expected behavior to fail an expectation if the original implementation gets called with different arguments than the one defined in the expect function?

defmodule Test do
 def call(arg), do: true
end

Test
|> expect(:call, 1, fn 2 -> true end)

Test.call(3)

Is the above supposed to fail verification?

edgurgel commented 1 year ago

Yup you should see a function clause error I think.

xantrac commented 1 year ago

Ok, it doesn't for me, but the counter expectation still verifies correctly.

edgurgel commented 1 year ago

Do you have a full test case file to share so we can replicate it? Cause testing quickly with mimic tests it seems to work as intended:

$ git diff
diff --git a/test/mimic_test.exs b/test/mimic_test.exs
index 5ffaa0e..92fd423 100644
--- a/test/mimic_test.exs
+++ b/test/mimic_test.exs
@@ -362,7 +362,7 @@ defmodule Mimic.Test do

     test "basic expectation" do
       Calculator
-      |> expect(:add, fn x, _y -> x + 2 end)
+      |> expect(:add, fn 3, _y -> 2 end)
       |> expect(:mult, fn x, _y -> x * 2 end)

       assert Calculator.add(4, :_) == 6

$ mix test
.....................

  1) test expect/4 private mode basic expectation (Mimic.Test)
     test/mimic_test.exs:363
     ** (FunctionClauseError) no function clause matching in anonymous fn/2 in Mimic.Test."test expect/4 private mode basic expectation"/1

     The following arguments were given to anonymous fn/2 in Mimic.Test."test expect/4 private mode basic expectation"/1:

         # 1
         4

         # 2
         :_

     code: assert Calculator.add(4, :_) == 6
     stacktrace:
       test/mimic_test.exs:365: anonymous fn/2 in Mimic.Test."test expect/4 private mode basic expectation"/1
       test/mimic_test.exs:368: (test)

....................................................

Finished in 0.6 seconds (0.6s async, 0.00s sync)
74 tests, 1 failure

Randomized with seed 443132
xantrac commented 1 year ago

This is the test

  describe "mark_order_ready" do
    test "updates the ready_at field and send a message to the costumer", %{account: account} do
      order = order_fixture(account)

      ExTwilio.Message
      |> expect(:create, 1, fn %{
                                 body: "this",
                                 from: "is not",
                                 to: "correct"
                               } ->
        nil
      end)

      Enum.each(order.order_items, &Orders.mark_order_item_dug(&1))
      order = Orders.get_order(order.id)

      assert order.ready_at == nil

      {:ok, order} = Orders.mark_order_ready(order)

      assert order.ready_at == Timex.now() |> DateTime.truncate(:second)
      Oban.drain_queue(queue: :default)
    end
  end

This is the implementation

  defp send_message(recipient, message) do
    if env() == :dev do
      Logger.info("SMS - from: #{phone_number()}, to: #{recipient}, message: #{message}")
    else
      ExTwilio.Message.create(%{from: phone_number(), body: message, to: recipient})
    end
  end

This test is green independently from the arguments. Changing the number of calls fails as expected.

edgurgel commented 1 year ago

Sorry I mean a minimal reproducible code that we can see failing. It's hard to understand what is going on here, how is the test helper setup to copy mimic etc etc

xantrac commented 1 year ago

Ok, I was able to get the test failing removing the Oban job and running the execution synchronously.

1) test mark_order_ready it updates the ready_at field and send a message to the costumer (OrdersTest)
     test/orders_test.exs:109
     ** (FunctionClauseError) no function clause matching in anonymous fn/1 in OrdersTest."test mark_order_ready it updates the ready_at field and send a message to the costumer"/1

     The following arguments were given to anonymous fn/1 in OrdersTest."test mark_order_ready it updates the ready_at field and send a message to the costumer"/1:

         # 1
         %{body: "Your order d41ef143 from is ready to pick up", from: nil, to: "6676162962"}
edgurgel commented 1 year ago

I see. Your issue might be related to async execution from a different process https://github.com/edgurgel/mimic#private-and-global-mode . You can either make it global or allow specific process if you have such info.

xantrac commented 1 year ago

Ok, I'll look into that and I'll report back.

xantrac commented 1 year ago

So I did make the expectation global with set_mimic_global() but I got the same outcome.