From 50626a3103db1b91587a2750fe20db0a26af1b24 Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Fri, 4 Aug 2023 12:24:45 -0700 Subject: [PATCH 1/3] Better verify/0 vs verify/1 tests ...by using more than one mock in each test. --- test/mox_test.exs | 118 ++++++++++++++++++++++++++++++++---------- test/support/mocks.ex | 1 + 2 files changed, 91 insertions(+), 28 deletions(-) diff --git a/test/mox_test.exs b/test/mox_test.exs index 5743546..7ebac67 100644 --- a/test/mox_test.exs +++ b/test/mox_test.exs @@ -351,16 +351,40 @@ defmodule MoxTest do verify!() expect(CalcMock, :add, fn x, y -> x + y end) + expect(SciCalcOnlyMock, :exponent, fn x, y -> x * y end) - message = ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, &verify!/0 + assert_raise(Mox.VerificationError, &verify!/0) + try do + verify!() + rescue + error in Mox.VerificationError -> + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + end - assert CalcMock.add(2, 3) == 5 + CalcMock.add(2, 3) + assert_raise(Mox.VerificationError, &verify!/0) + try do + verify!() + rescue + error in Mox.VerificationError -> + refute error.message =~ ~r"expected CalcMock.add/2" + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + end + + SciCalcOnlyMock.exponent(2, 3) verify!() - expect(CalcMock, :add, fn x, y -> x + y end) - message = ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" - assert_raise Mox.VerificationError, message, &verify!/0 + # Adding another expected call makes verification fail again + expect(CalcMock, :add, fn x, y -> x + y end) + assert_raise(Mox.VerificationError, &verify!/0) + try do + verify!() + rescue + error in Mox.VerificationError -> + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" + end end test "verifies all mocks for the current process in global mode" do @@ -368,22 +392,43 @@ defmodule MoxTest do verify!() expect(CalcMock, :add, fn x, y -> x + y end) + expect(SciCalcOnlyMock, :exponent, fn x, y -> x * y end) - message = ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, &verify!/0 + assert_raise(Mox.VerificationError, &verify!/0) + try do + verify!() + rescue + error in Mox.VerificationError -> + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + end - task = - Task.async(fn -> - assert CalcMock.add(2, 3) == 5 - end) + Task.async(fn -> SciCalcOnlyMock.exponent(2, 4) end) + |> Task.await() - Task.await(task) + assert_raise(Mox.VerificationError, &verify!/0) + try do + verify!() + rescue + error in Mox.VerificationError -> + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" + end + + Task.async(fn -> CalcMock.add(5, 6) end) + |> Task.await() verify!() - expect(CalcMock, :add, fn x, y -> x + y end) - message = ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" - assert_raise Mox.VerificationError, message, &verify!/0 + expect(CalcMock, :add, fn x, y -> x + y end) + assert_raise(Mox.VerificationError, &verify!/0) + try do + verify!() + rescue + error in Mox.VerificationError -> + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" + end end end @@ -392,40 +437,57 @@ defmodule MoxTest do set_mox_private() verify!(CalcMock) + verify!(SciCalcOnlyMock) expect(CalcMock, :add, fn x, y -> x + y end) + expect(SciCalcOnlyMock, :exponent, fn x, y -> x * y end) message = ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, &verify!/0 + assert_raise Mox.VerificationError, message, fn -> verify!(CalcMock) end + message = ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + assert_raise Mox.VerificationError, message, fn -> verify!(SciCalcOnlyMock) end - assert CalcMock.add(2, 3) == 5 + CalcMock.add(2, 3) verify!(CalcMock) - expect(CalcMock, :add, fn x, y -> x + y end) + message = ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + assert_raise Mox.VerificationError, message, fn -> verify!(SciCalcOnlyMock) end + + SciCalcOnlyMock.exponent(2, 3) + verify!(CalcMock) + verify!(SciCalcOnlyMock) + expect(CalcMock, :add, fn x, y -> x + y end) message = ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" - assert_raise Mox.VerificationError, message, &verify!/0 + assert_raise Mox.VerificationError, message, fn -> verify!(CalcMock) end + verify!(SciCalcOnlyMock) end test "verifies all mocks for current process in global mode" do set_mox_global() verify!(CalcMock) + verify!(SciCalcOnlyMock) expect(CalcMock, :add, fn x, y -> x + y end) + expect(SciCalcOnlyMock, :exponent, fn x, y -> x * y end) message = ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, &verify!/0 + assert_raise Mox.VerificationError, message, fn -> verify!(CalcMock) end + message = ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + assert_raise Mox.VerificationError, message, fn -> verify!(SciCalcOnlyMock) end - task = - Task.async(fn -> - assert CalcMock.add(2, 3) == 5 - end) - - Task.await(task) + Task.async(fn -> CalcMock.add(2, 3) end) + |> Task.await() + verify!(CalcMock) + message = ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + assert_raise Mox.VerificationError, message, fn -> verify!(SciCalcOnlyMock) end + SciCalcOnlyMock.exponent(2, 3) verify!(CalcMock) - expect(CalcMock, :add, fn x, y -> x + y end) + verify!(SciCalcOnlyMock) + expect(CalcMock, :add, fn x, y -> x + y end) message = ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" assert_raise Mox.VerificationError, message, &verify!/0 + verify!(SciCalcOnlyMock) end test "raises if a non-mock is given" do diff --git a/test/support/mocks.ex b/test/support/mocks.ex index bd56b15..95a7bc8 100644 --- a/test/support/mocks.ex +++ b/test/support/mocks.ex @@ -1,4 +1,5 @@ Mox.defmock(CalcMock, for: Calculator) +Mox.defmock(SciCalcOnlyMock, for: ScientificCalculator) Mox.defmock(SciCalcMock, for: [Calculator, ScientificCalculator]) Mox.defmock(SciCalcMockWithoutOptional, From 1ee925f7051fa475b2063ed2ebd1f6304921326b Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Thu, 10 Aug 2023 06:23:46 -0700 Subject: [PATCH 2/3] Dramatically reduce complexity of verify!/0 test assertions ...by capturing the return value of `assert_raise` rather than doing a verbose try/rescue w/ assertions. This approach has the added benefit that the test will begin failing if the verify!/0 call fails to raise an exception when it should! --- test/mox_test.exs | 66 +++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/test/mox_test.exs b/test/mox_test.exs index 7ebac67..66180b4 100644 --- a/test/mox_test.exs +++ b/test/mox_test.exs @@ -353,38 +353,23 @@ defmodule MoxTest do expect(CalcMock, :add, fn x, y -> x + y end) expect(SciCalcOnlyMock, :exponent, fn x, y -> x * y end) - assert_raise(Mox.VerificationError, &verify!/0) - try do - verify!() - rescue - error in Mox.VerificationError -> - assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" - end + error = assert_raise(Mox.VerificationError, &verify!/0) + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" CalcMock.add(2, 3) - assert_raise(Mox.VerificationError, &verify!/0) - try do - verify!() - rescue - error in Mox.VerificationError -> - refute error.message =~ ~r"expected CalcMock.add/2" - assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" - end + error = assert_raise(Mox.VerificationError, &verify!/0) + refute error.message =~ ~r"expected CalcMock.add/2" + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" SciCalcOnlyMock.exponent(2, 3) verify!() # Adding another expected call makes verification fail again expect(CalcMock, :add, fn x, y -> x + y end) - assert_raise(Mox.VerificationError, &verify!/0) - try do - verify!() - rescue - error in Mox.VerificationError -> - assert error.message =~ ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" - refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" - end + error = assert_raise(Mox.VerificationError, &verify!/0) + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" end test "verifies all mocks for the current process in global mode" do @@ -394,26 +379,16 @@ defmodule MoxTest do expect(CalcMock, :add, fn x, y -> x + y end) expect(SciCalcOnlyMock, :exponent, fn x, y -> x * y end) - assert_raise(Mox.VerificationError, &verify!/0) - try do - verify!() - rescue - error in Mox.VerificationError -> - assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" - end + error = assert_raise(Mox.VerificationError, &verify!/0) + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" Task.async(fn -> SciCalcOnlyMock.exponent(2, 4) end) |> Task.await() - assert_raise(Mox.VerificationError, &verify!/0) - try do - verify!() - rescue - error in Mox.VerificationError -> - assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" - end + error = assert_raise(Mox.VerificationError, &verify!/0) + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" Task.async(fn -> CalcMock.add(5, 6) end) |> Task.await() @@ -421,14 +396,9 @@ defmodule MoxTest do verify!() expect(CalcMock, :add, fn x, y -> x + y end) - assert_raise(Mox.VerificationError, &verify!/0) - try do - verify!() - rescue - error in Mox.VerificationError -> - assert error.message =~ ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" - refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" - end + error = assert_raise(Mox.VerificationError, &verify!/0) + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" end end From 999810cfba96b31b6edefd2b9e7f346072c5cfbb Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Thu, 10 Aug 2023 06:28:09 -0700 Subject: [PATCH 3/3] Increase coverage of verify!/1 tests by capturing assert_raise error which then lets us perform `refute` checks on the error message in addition to asserting what the error message *does* contain. --- test/mox_test.exs | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/test/mox_test.exs b/test/mox_test.exs index 66180b4..4569e4f 100644 --- a/test/mox_test.exs +++ b/test/mox_test.exs @@ -411,23 +411,29 @@ defmodule MoxTest do expect(CalcMock, :add, fn x, y -> x + y end) expect(SciCalcOnlyMock, :exponent, fn x, y -> x * y end) - message = ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, fn -> verify!(CalcMock) end - message = ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, fn -> verify!(SciCalcOnlyMock) end + error = assert_raise(Mox.VerificationError, fn -> verify!(CalcMock) end) + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" + + error = assert_raise(Mox.VerificationError, fn -> verify!(SciCalcOnlyMock) end) + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + refute error.message =~ ~r"expected CalcMock.add/2" CalcMock.add(2, 3) verify!(CalcMock) - message = ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, fn -> verify!(SciCalcOnlyMock) end + + error = assert_raise(Mox.VerificationError, fn -> verify!(SciCalcOnlyMock) end) + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + refute error.message =~ ~r"expected CalcMock.add/2" SciCalcOnlyMock.exponent(2, 3) verify!(CalcMock) verify!(SciCalcOnlyMock) expect(CalcMock, :add, fn x, y -> x + y end) - message = ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" - assert_raise Mox.VerificationError, message, fn -> verify!(CalcMock) end + error = assert_raise Mox.VerificationError, fn -> verify!(CalcMock) end + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" verify!(SciCalcOnlyMock) end @@ -439,24 +445,32 @@ defmodule MoxTest do expect(CalcMock, :add, fn x, y -> x + y end) expect(SciCalcOnlyMock, :exponent, fn x, y -> x * y end) - message = ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, fn -> verify!(CalcMock) end - message = ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, fn -> verify!(SciCalcOnlyMock) end + error = assert_raise(Mox.VerificationError, fn -> verify!(CalcMock) end) + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked once but it was invoked 0 times" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" + + error = assert_raise(Mox.VerificationError, fn -> verify!(SciCalcOnlyMock) end) + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + refute error.message =~ ~r"expected CalcMock.add/2" Task.async(fn -> CalcMock.add(2, 3) end) |> Task.await() verify!(CalcMock) - message = ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" - assert_raise Mox.VerificationError, message, fn -> verify!(SciCalcOnlyMock) end + + error = assert_raise(Mox.VerificationError, fn -> verify!(SciCalcOnlyMock) end) + assert error.message =~ ~r"expected SciCalcOnlyMock.exponent/2 to be invoked once but it was invoked 0 times" + refute error.message =~ ~r"expected CalcMock.add/2" SciCalcOnlyMock.exponent(2, 3) verify!(CalcMock) verify!(SciCalcOnlyMock) expect(CalcMock, :add, fn x, y -> x + y end) - message = ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" - assert_raise Mox.VerificationError, message, &verify!/0 + + error = assert_raise(Mox.VerificationError, &verify!/0) + assert error.message =~ ~r"expected CalcMock.add/2 to be invoked 2 times but it was invoked once" + refute error.message =~ ~r"expected SciCalcOnlyMock.exponent/2" + verify!(SciCalcOnlyMock) end