diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..d304ff3 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,3 @@ +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/lib/mock.ex b/lib/mock.ex index c8aac2d..430e936 100644 --- a/lib/mock.ex +++ b/lib/mock.ex @@ -42,7 +42,9 @@ defmodule Mock do defmacro with_mock(mock_module, opts \\ [], mocks, do: test) do quote do unquote(__MODULE__).with_mocks( - [{unquote(mock_module), unquote(opts), unquote(mocks)}], do: unquote(test)) + [{unquote(mock_module), unquote(opts), unquote(mocks)}], + do: unquote(test) + ) end end @@ -85,7 +87,11 @@ defmodule Mock do quote do test unquote(test_name) do unquote(__MODULE__).with_mock( - unquote(mock_module), unquote(opts), unquote(mocks), unquote(test_block)) + unquote(mock_module), + unquote(opts), + unquote(mocks), + unquote(test_block) + ) end end end @@ -114,7 +120,11 @@ defmodule Mock do quote do test unquote(test_name), unquote(context) do unquote(__MODULE__).with_mock( - unquote(mock_module), unquote(opts), unquote(mocks), unquote(test_block)) + unquote(mock_module), + unquote(opts), + unquote(mocks), + unquote(test_block) + ) end end end @@ -138,51 +148,52 @@ defmodule Mock do end @doc """ - Use inside a `with_mock` block to determine whether - a mocked function was called as expected. + Use inside a `with_mock` block to determine whether + a mocked function was called as expected. - Pass `:_` as a function argument for wildcard matches. + Pass `:_` as a function argument for wildcard matches. - ## Example + ## Example - assert called HTTPotion.get("http://example.com") + assert called HTTPotion.get("http://example.com") - # Matches any invocation - assert called HTTPotion.get(:_) - """ - defmacro called({ {:., _, [ module , f ]} , _, args }) do + # Matches any invocation + assert called HTTPotion.get(:_) + """ + defmacro called({{:., _, [module, f]}, _, args}) do quote do - :meck.called unquote(module), unquote(f), unquote(args) + :meck.called(unquote(module), unquote(f), unquote(args)) end end @doc """ - Use inside a `with_mock` block to determine whether - a mocked function was called as expected. If the assertion fails, - the calls that were received are displayed in the assertion message. + Use inside a `with_mock` block to determine whether + a mocked function was called as expected. If the assertion fails, + the calls that were received are displayed in the assertion message. - Pass `:_` as a function argument for wildcard matches. + Pass `:_` as a function argument for wildcard matches. - ## Example + ## Example - assert_called HTTPotion.get("http://example.com") + assert_called HTTPotion.get("http://example.com") - # Matches any invocation - assert_called HTTPotion.get(:_) - """ + # Matches any invocation + assert_called HTTPotion.get(:_) + """ defmacro assert_called({{:., _, [module, f]}, _, args}) do quote do unquoted_module = unquote(module) value = :meck.called(unquoted_module, unquote(f), unquote(args)) unless value do - calls = unquoted_module - |> :meck.history() - |> Enum.with_index() - |> Enum.map(fn {{_, {m, f, a}, ret}, i} -> - "#{i}. #{m}.#{f}(#{a |> Enum.map(&Kernel.inspect/1) |> Enum.join(",")}) (returned #{inspect ret})" - end) - |> Enum.join("\n") + calls = + unquoted_module + |> :meck.history() + |> Enum.with_index() + |> Enum.map(fn {{_, {m, f, a}, ret}, i} -> + "#{i}. #{m}.#{f}(#{a |> Enum.map(&Kernel.inspect/1) |> Enum.join(",")}) (returned #{inspect(ret)})" + end) + |> Enum.join("\n") raise ExUnit.AssertionError, message: "Expected call but did not receive it. Calls which were received:\n\n#{calls}" @@ -213,9 +224,12 @@ defmodule Mock do num_calls = :meck.num_calls(unquoted_module, unquoted_f, unquoted_args) if num_calls != unquoted_call_times do - mfa_str = "#{unquoted_module}.#{unquoted_f}(#{unquoted_args |> Enum.map(&Kernel.inspect/1) |> Enum.join(", ")})" + mfa_str = + "#{unquoted_module}.#{unquoted_f}(#{unquoted_args |> Enum.map(&Kernel.inspect/1) |> Enum.join(", ")})" + raise ExUnit.AssertionError, - message: "Expected #{mfa_str} to be called exactly #{unquoted_call_times} time(s), but it was called (number of calls: #{num_calls})" + message: + "Expected #{mfa_str} to be called exactly #{unquoted_call_times} time(s), but it was called (number of calls: #{num_calls})" end end end @@ -243,27 +257,30 @@ defmodule Mock do actual_called_count = :meck.num_calls(unquoted_module, unquoted_f, unquoted_args) if actual_called_count < unquoted_expected_times do - mfa_str = "#{unquoted_module}.#{unquoted_f}(#{unquoted_args |> Enum.map(&Kernel.inspect/1) |> Enum.join(", ")})" + mfa_str = + "#{unquoted_module}.#{unquoted_f}(#{unquoted_args |> Enum.map(&Kernel.inspect/1) |> Enum.join(", ")})" + raise ExUnit.AssertionError, - message: "Expected #{mfa_str} to be called at least #{unquoted_expected_times} time(s), but it was called (number of calls: #{actual_called_count})" + message: + "Expected #{mfa_str} to be called at least #{unquoted_expected_times} time(s), but it was called (number of calls: #{actual_called_count})" end end end @doc """ - Use inside a `with_mock` block to check if - a mocked function was NOT called. If the assertion fails, - the number of calls is displayed in the assertion message. + Use inside a `with_mock` block to check if + a mocked function was NOT called. If the assertion fails, + the number of calls is displayed in the assertion message. - Pass `:_` as a function argument for wildcard matches. + Pass `:_` as a function argument for wildcard matches. - ## Example + ## Example - assert_not_called HTTPotion.get("http://example.com") + assert_not_called HTTPotion.get("http://example.com") - # Matches any invocation - assert_not_called HTTPotion.get(:_) - """ + # Matches any invocation + assert_not_called HTTPotion.get(:_) + """ defmacro assert_not_called({{:., _, [module, f]}, _, args}) do quote do unquoted_module = unquote(module) @@ -272,9 +289,12 @@ defmodule Mock do num_calls = :meck.num_calls(unquoted_module, unquoted_f, unquoted_args) if num_calls > 0 do - mfa_str = "#{unquoted_module}.#{unquoted_f}(#{unquoted_args |> Enum.map(&Kernel.inspect/1) |> Enum.join(", ")})" + mfa_str = + "#{unquoted_module}.#{unquoted_f}(#{unquoted_args |> Enum.map(&Kernel.inspect/1) |> Enum.join(", ")})" + raise ExUnit.AssertionError, - message: "Expected #{mfa_str} not to be called, but it was called (number of calls: #{num_calls})" + message: + "Expected #{mfa_str} not to be called, but it was called (number of calls: #{num_calls})" end end end @@ -365,11 +385,65 @@ defmodule Mock do end end + @doc """ + Shortcut to avoid multiple blocks when a test requires multiple + mocks. + + For full description see `test_with_mocks`. + + ## Example + + test_with_mocks "test_name", [{HTTPotion,[], + [get: fn(_url) -> "" end]}] do + HTTPotion.get("http://example.com") + assert called HTTPotion.get("http://example.com") + end + """ + defmacro test_with_mocks(test_name, mocks, test_block) do + quote do + test unquote(test_name) do + unquote(__MODULE__).with_mocks( + unquote(mocks), + unquote(test_block) + ) + end + end + end + + @doc """ + Shortcut to avoid multiple blocks when a test requires multiple + mocks. Accepts a context argument enabling information to be shared + between callbacks and the test. + + For full description see `test_with_mocks`. + + ## Example + + test_with_mocks "test_name", %{foo: foo} [{HTTPotion,[], + [get: fn(_url) -> "" end]}] do + HTTPotion.get("http://example.com") + assert called HTTPotion.get("http://example.com") + assert foo == "bar" + end + """ + defmacro test_with_mocks(test_name, context, mocks, test_block) do + quote do + test unquote(test_name), unquote(context) do + unquote(__MODULE__).with_mocks( + unquote(mocks), + unquote(test_block) + ) + end + end + end + + ###################################################### + # Helper macro to mock modules. Intended to be called only within this module # but not defined as `defmacrop` due to the scope within which it's used. defmacro mock_modules(mocks) do quote do - Enum.reduce(unquote(mocks), [], fn({m, opts, mock_fns}, ms) -> + Enum.reduce(unquote(mocks), [], fn {m, opts, mock_fns}, ms -> unless m in ms do # :meck.validate will throw an error if trying to validate # a module that was not mocked @@ -385,14 +459,15 @@ defmodule Mock do unquote(__MODULE__)._install_mock(m, mock_fns) true = :meck.validate(m) - [ m | ms] |> Enum.uniq + [m | ms] |> Enum.uniq() end) end end @doc false def _install_mock(_, []), do: :ok - def _install_mock(mock_module, [ {fn_name, value} | tail ]) do + + def _install_mock(mock_module, [{fn_name, value} | tail]) do :meck.expect(mock_module, fn_name, value) _install_mock(mock_module, tail) end diff --git a/mix.exs b/mix.exs index 36253a6..81f46bc 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,8 @@ defmodule Mock.Mixfile do @version "0.3.8" def project do - [ app: :mock, + [ + app: :mock, name: "Mock", version: @version, elixir: "~> 1.0", @@ -13,7 +14,8 @@ defmodule Mock.Mixfile do test_coverage: [tool: ExCoveralls], docs: [source_ref: "v#{@version}", main: "Mock"], preferred_cli_env: [coveralls: :test, "coveralls.detail": :test, "coveralls.post": :test], - deps: deps() ] + deps: deps() + ] end defp deps do @@ -49,7 +51,7 @@ defmodule Mock.Mixfile do "matt.freer", "Mikhail S. Pobolovets", "parroty", - "xieyunzi", + "xieyunzi" ], maintainers: [ "Daniel Olshansky (olshansky.daniel@gmail.com)", @@ -58,7 +60,7 @@ defmodule Mock.Mixfile do licenses: ["MIT"], links: %{ "GitHub" => "https://github.com/jjh42/mock", - "Docs" => "https://jjh42.github.io/mock" + "Docs" => "https://jjh42.github.io/mock" } ] end diff --git a/mix.lock b/mix.lock index 089f90a..2fc16cc 100644 --- a/mix.lock +++ b/mix.lock @@ -1,21 +1,24 @@ %{ - "certifi": {:hex, :certifi, "2.0.0", "a0c0e475107135f76b8c1d5bc7efb33cd3815cb3cf3dea7aefdd174dabead064", [:rebar3], [], "hexpm", "fdc6066ceeccb3aa14049ab6edf0b9af3b64ae1b0db2a92d5c52146f373bbb1c"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "docs_ghpages": {:git, "https://github.com/jjh42/docs_ghpages.git", "48026d548475a5b03e4a39282d0cbd9d9c4973d6", []}, "earmark": {:hex, :earmark, "1.2.3", "206eb2e2ac1a794aa5256f3982de7a76bf4579ff91cb28d0e17ea2c9491e46a4", [:mix], [], "hexpm", "3b1dcad3067985dd8618c38399a8ee9c4e652d52a17a4aae7a6d6fc4fcc24856"}, - "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "dc87f778d8260da0189a622f62790f6202af72f2f3dee6e78d91a18dd2fcd137"}, - "excoveralls": {:hex, :excoveralls, "0.7.2", "f69ede8c122ccd3b60afc775348a53fc8c39fe4278aee2f538f0d81cc5e7ff3a", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "ef8fc1c6014b16a68dccfba3513aa41283d731eeaf8a1b704bbb072cb1ab89cb"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, + "ex_doc": {:hex, :ex_doc, "0.35.1", "de804c590d3df2d9d5b8aec77d758b00c814b356119b3d4455e4b8a8687aecaf", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2121c6402c8d44b05622677b761371a759143b958c6c19f6558ff64d0aed40df"}, + "excoveralls": {:hex, :excoveralls, "0.7.5", "339e433e5d3bce09400dc8de7b9040741a409c93917849916c136a0f51fdc183", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "36422936691b6a8a728fe42c528e7b2719b2fde1a56d19fc7e3de31cb2271017"}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"}, - "hackney": {:hex, :hackney, "1.9.0", "51c506afc0a365868469dcfc79a9d0b94d896ec741cfd5bd338f49a5ec515bfe", [:rebar3], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e38f4a7937b6dfc5fa87403ece26b1826bc81838f09ac57fabf2f7a9885fe818"}, + "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "hoedown": {:git, "https://github.com/hoedown/hoedown.git", "980b9c549b4348d50b683ecee6abee470b98acda", []}, - "idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fc1a2f7340c422650504b1662f28fdf381f34cbd30664e8491744e52c9511d40"}, - "jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], [], "hexpm", "b4c5d3230b397c8d95579e4a3d72826bb6463160130ccf4182f5be8579b5f44c"}, - "makeup": {:hex, :makeup, "0.5.1", "966c5c2296da272d42f1de178c1d135e432662eca795d6dc12e5e8787514edf7", [:mix], [{:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "259748a45dfcf5f49765a7c29c9594791c82de23e22d7a3e6e59533fe8e8935b"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "393d17c5a648e3b30522b2a4743bd1dc3533e1227c8c2823ebe8c3a8e5be5913"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"}, + "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, + "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, "markdown": {:git, "https://github.com/devinus/markdown.git", "d065dbcc4e242a85ca2516fdadd0082712871fd8", []}, "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm", "7a4c8e1115a2732a67d7624e28cf6c9f30c66711a9e92928e745c255887ba465"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm", "4ababf5c44164f161872704e1cfbecab3935fdebec66c72905abaad0e6e5cef6"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm", "4f8805eb5c8a939cf2359367cb651a3180b27dfb48444846be2613d79355d65e"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm", "da1d9bef8a092cc7e1e51f1298037a5ddfb0f657fe862dfe7ba4c5807b551c29"}, + "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, } diff --git a/test/mock_setup_test.exs b/test/mock_setup_test.exs index 96b97ab..40961d4 100644 --- a/test/mock_setup_test.exs +++ b/test/mock_setup_test.exs @@ -1,11 +1,11 @@ -Code.require_file "test_helper.exs", __DIR__ +Code.require_file("test_helper.exs", __DIR__) defmodule MockSetupTest do use ExUnit.Case, async: false import Mock setup_with_mocks([ - {Map, [:passthrough], [get: fn(%{}, "http://example.com") -> "" end]} + {Map, [:passthrough], [get: fn %{}, "http://example.com" -> "" end]} ]) do foo = "bar" {:ok, foo: foo} @@ -20,26 +20,29 @@ defmodule MockSetupTest do end test_with_mock "setup_with_mocks respects test specific override", Map, [:passthrough], - [get: fn(%{}, "http://example.com") -> "override" end] do - + get: fn %{}, "http://example.com" -> "override" end do assert Map.get(%{}, "http://example.com") == "override" end - test_with_mock "setup_with_mocks with test context respects test specific override", %{foo: "bar"}, - Map, [], [get: fn(%{}, "http://example.com") -> "override" end] do - + test_with_mock "setup_with_mocks with test context respects test specific override", + %{foo: "bar"}, + Map, + [], + get: fn %{}, "http://example.com" -> "override" end do assert Map.get(%{}, "http://example.com") == "override" end - end defmodule MockSetupTestWithContext do use ExUnit.Case, async: false import Mock - setup_with_mocks([ - {Map, [:passthrough], [get: fn(%{}, "http://example.com") -> "" end]} - ], context) do + setup_with_mocks( + [ + {Map, [:passthrough], [get: fn %{}, "http://example.com" -> "" end]} + ], + context + ) do {:ok, test_string: Atom.to_string(context.test)} end @@ -51,5 +54,4 @@ defmodule MockSetupTestWithContext do assert Map.get(%{}, "http://example.com") == "" assert test_string == "test setup_with_mocks with setup context and test context" end - end diff --git a/test/mock_test.exs b/test/mock_test.exs index 6340414..dd19850 100644 --- a/test/mock_test.exs +++ b/test/mock_test.exs @@ -1,5 +1,4 @@ -Code.require_file "test_helper.exs", __DIR__ - +Code.require_file("test_helper.exs", __DIR__) defmodule MockTest do use ExUnit.Case, async: false @@ -12,18 +11,18 @@ defmodule MockTest do test "simple mock" do with_mock String, - [reverse: fn(x) -> 2*x end] do + reverse: fn x -> 2 * x end do assert String.reverse(3) == 6 end end test "mock functions with multiple returns" do - with_mock(Map, [ + with_mock(Map, get: fn - (%{}, "http://example.com") -> "Hello from example.com" - (%{}, "http://example.org") -> "example.org says hi" + %{}, "http://example.com" -> "Hello from example.com" + %{}, "http://example.org" -> "example.org says hi" end - ]) do + ) do assert Map.get(%{}, "http://example.com") == "Hello from example.com" assert Map.get(%{}, "http://example.org") == "example.org says hi" end @@ -31,13 +30,8 @@ defmodule MockTest do test "multiple mocks" do with_mocks([ - {Map, - [], - [get: fn(%{}, "http://example.com") -> "" end]}, - {String, - [], - [reverse: fn(x) -> 2*x end, - length: fn(_x) -> :ok end]} + {Map, [], [get: fn %{}, "http://example.com" -> "" end]}, + {String, [], [reverse: fn x -> 2 * x end, length: fn _x -> :ok end]} ]) do assert Map.get(%{}, "http://example.com") == "" assert String.reverse(3) == 6 @@ -47,28 +41,28 @@ defmodule MockTest do test "mock functions with different arity" do with_mock String, - [slice: fn(string, _range) -> string end, - slice: fn(string, _range, _len) -> string end] - do + slice: fn string, _range -> string end, + slice: fn string, _range, _len -> string end do assert String.slice("test", 1..3) == "test" assert String.slice("test", 1, 3) == "test" end end test "mock returns the result" do - result = with_mock String, - [reverse: fn(x) -> 2*x end] do - assert String.reverse(3) == 6 - String.reverse(3) - end + result = + with_mock String, + reverse: fn x -> 2 * x end do + assert String.reverse(3) == 6 + String.reverse(3) + end + assert result == 6 end test "mock returns multiples results in sequence" do - with_mock String, [ + with_mock String, reverse: [in_series([:_], [:a, :b, :c])], - slice: [in_series([1, 2], [:x, :y, :z])] - ] do + slice: [in_series([1, 2], [:x, :y, :z])] do assert String.reverse(1) == :a assert String.reverse(1) == :b assert String.reverse(1) == :c @@ -81,18 +75,18 @@ defmodule MockTest do test "called" do with_mock String, - [reverse: fn(x) -> 2*x end, - length: fn(_x) -> :ok end] do - String.reverse 3 - assert :meck.called String, :reverse, [3] - assert called String.reverse(3) - refute called String.reverse(2) - refute called String.length(3) + reverse: fn x -> 2 * x end, + length: fn _x -> :ok end do + String.reverse(3) + assert :meck.called(String, :reverse, [3]) + assert called(String.reverse(3)) + refute called(String.reverse(2)) + refute called(String.length(3)) end end test "assert_called" do - with_mock String, [reverse: fn(x) -> 2*x end] do + with_mock String, reverse: fn x -> 2 * x end do String.reverse(3) assert_called(String.reverse(3)) @@ -110,7 +104,7 @@ defmodule MockTest do end test "assert_called_exactly" do - with_mock String, [reverse: fn(x) -> 2*x end] do + with_mock String, reverse: fn x -> 2 * x end do String.reverse(2) String.reverse(2) String.reverse(2) @@ -128,7 +122,7 @@ defmodule MockTest do end test "assert_called_at_least" do - with_mock String, [reverse: fn(x) -> 2*x end] do + with_mock String, reverse: fn x -> 2 * x end do String.reverse(2) String.reverse(2) String.reverse(2) @@ -148,7 +142,7 @@ defmodule MockTest do test "assert_not_called" do with_mock String, - [reverse: fn(x) -> 2*x end] do + reverse: fn x -> 2 * x end do String.reverse(3) String.reverse(3) assert_not_called(String.reverse(2)) @@ -165,48 +159,66 @@ defmodule MockTest do end test_with_mock "test_with_mock", - String, - [reverse: fn(_x) -> :ok end] do - assert String.reverse 3 - assert called String.reverse(3) - refute called String.reverse(4) + String, + reverse: fn _x -> :ok end do + assert String.reverse(3) + assert called(String.reverse(3)) + refute called(String.reverse(4)) end - test_with_mock "test_with_mock with context", %{foo: foo}, String, [], - [reverse: fn(_x) -> :ok end] do - assert String.reverse 3 + test_with_mock "test_with_mock with context", %{foo: foo}, String, [], reverse: fn _x -> :ok end do + assert String.reverse(3) assert foo == "bar" - assert called String.reverse(3) - refute called String.reverse(4) + assert called(String.reverse(3)) + refute called(String.reverse(4)) end - test_with_mock "passthrough option", Map, [:passthrough], - [] do + test_with_mock "passthrough option", Map, [:passthrough], [] do hd = Map.put(Map.new(), :a, 1) assert Map.get(hd, :a) == 1 - assert called Map.new() - assert called Map.get(hd, :a) - refute called Map.get(hd, :b) + assert called(Map.new()) + assert called(Map.get(hd, :a)) + refute called(Map.get(hd, :b)) end test_with_mock "passthrough in anon mock function", String, [:passthrough], - [reverse: fn x -> passthrough([x]) <> "!" end] do + reverse: fn x -> passthrough([x]) <> "!" end do assert String.reverse("xyz") == "zyx!" - assert called String.reverse("xyz") + assert called(String.reverse("xyz")) end test "restore after exception" do assert String.downcase("A") == "a" + try do with_mock String, - [downcase: fn(x) -> x end] do + downcase: fn x -> x end do assert String.downcase("A") == "A" raise "some error" end rescue RuntimeError -> :ok end + assert String.downcase("A") == "a" end + test_with_mocks "test_with_mocks/3", [ + {Map, [], [get: fn %{}, "http://example.com" -> "" end]}, + {String, [], [reverse: fn x -> 2 * x end, length: fn _x -> :ok end]} + ] do + assert Map.get(%{}, "http://example.com") == "" + assert String.reverse(3) == 6 + assert String.length(3) == :ok + end + + test_with_mocks "test_with_mocks/4", %{foo: foo}, [ + {Map, [], [get: fn %{}, "http://example.com" -> "" end]}, + {String, [], [reverse: fn x -> 2 * x end, length: fn _x -> :ok end]} + ] do + assert Map.get(%{}, "http://example.com") == "" + assert String.reverse(3) == 6 + assert String.length(3) == :ok + assert foo == "bar" + end end diff --git a/test/test_helper.exs b/test/test_helper.exs index 4b8b246..869559e 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1 +1 @@ -ExUnit.start +ExUnit.start()