Repository: edgurgel/mimic (elixir)

Issue:
Calling `stub_with/2` with a second module that doesn't exist causes Mimic to fail in unpredictable ways
It's late, so I haven't crafted a reproducer, but I renamed a module that was being stubbed elsewhere in my code and didn't change it there. Then a bunch of tests failed saying that other completely unrelated modules hadn't been copied, when they definitely had. Other times the Mimic genserver crashed outright.

Pull request description:
Fix stub with undefined
Fixes #54 

Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index dc62a5d..ebbc4c0 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -12,8 +12,8 @@ jobs:
       - name: Install OTP and Elixir
         uses: erlef/setup-elixir@v1
         with:
-          otp-version: 23.1.1
-          elixir-version: 1.11.2
+          otp-version: 24.3
+          elixir-version: 1.13.3
 
       - name: Install dependencies
         run: mix deps.get
@@ -37,8 +37,6 @@ jobs:
           - otp: 24.3
             elixir: 1.13.3
             coverage: true
-          - otp: 23.1.1
-            elixir: 1.11.3
           - otp: 24.3
             elixir: 1.12.3
     env:
diff --git a/lib/mimic.ex b/lib/mimic.ex
index 52bf548..7326297 100644
--- a/lib/mimic.ex
+++ b/lib/mimic.ex
@@ -182,6 +182,8 @@ defmodule Mimic do
   """
   @spec stub_with(module(), module()) :: module()
   def stub_with(module, mocking_module) do
+    raise_if_module_not_defined!(mocking_module)
+
     module
     |> Server.stub_with(mocking_module)
     |> validate_server_response(:stub)
@@ -468,6 +470,12 @@ defmodule Mimic do
     end
   end
 
+  defp raise_if_module_not_defined!(module) do
+    unless Code.ensure_loaded?(module) do
+      raise ArgumentError, "Module #{inspect(module)} not defined"
+    end
+  end
+
   defp validate_server_response({:ok, module}, _action), do: module
 
   defp validate_server_response({:error, :not_global_owner}, :reject) do


Test patch:
diff --git a/test/mimic_test.exs b/test/mimic_test.exs
index 5ffaa0e..cdde541 100644
--- a/test/mimic_test.exs
+++ b/test/mimic_test.exs
@@ -112,7 +112,7 @@ defmodule Mimic.Test do
     end
   end
 
-  describe "stub_with/1 private mode" do
+  describe "stub_with/2 private mode" do
     setup :set_mimic_private
 
     test "called multiple times" do
@@ -127,6 +127,22 @@ defmodule Mimic.Test do
 
       assert_raise Mimic.UnexpectedCallError, fn -> Calculator.mult(4, 9) end
     end
+
+    test "undefined mocking module" do
+      assert_raise ArgumentError,
+                   "Module MissingModule not defined",
+                   fn ->
+                     stub_with(Calculator, MissingModule)
+                   end
+    end
+
+    test "undefined mocked module" do
+      assert_raise ArgumentError,
+                   "Module MissingModule has not been copied.  See docs for Mimic.copy/1",
+                   fn ->
+                     stub_with(MissingModule, InverseCalculator)
+                   end
+    end
   end
 
   describe "stub/3 private mode" do