Packages

An Elixir library to make function delegation testable.

Current section

7 Versions

Jump to

Compare versions

11 files changed
+143 additions
-122 deletions
  @@ -39,14 +39,14 @@ end
39 39 ```
40 40
41 41 You can delegate functions calls to another module by using the `Delx` module
42 - and calling the `defdel/2` macro in the module body. It has the same API as
42 + and calling the `defdelegate/2` macro in the module body. It has the same API as
43 43 Elixir's own `Kernel.defdelegate/2` macro.
44 44
45 45 ```elixir
46 46 defmodule Greeter do
47 47 use Delx, otp_app: :greeter
48 48
49 - defdel hello(name), to: Greeter.StringGreeter
49 + defdelegate hello(name), to: Greeter.StringGreeter
50 50 end
51 51
52 52 Greeter.hello("Tobi")
  @@ -63,11 +63,11 @@ effects.
63 63
64 64 Delx brings it's own test assertions.
65 65
66 - All you need to do is to activate delegation stubbing for your test
67 - environment by putting the following line in your `config/test.exs`:
66 + All you need to do is to activate delegation mocking for your test environment
67 + by putting the following line in your `config/test.exs`:
68 68
69 69 ```elixir
70 - config :greeter, Delx, stub: true
70 + config :greeter, Delx, mock: true
71 71 ```
72 72
73 73 Then in your tests, you can import `Delx.TestAssertions` and use the
  @@ -87,8 +87,8 @@ defmodule GreeterTest do
87 87 end
88 88 ```
89 89
90 - Note that once you activate stubbing all delegated functions do not return
91 - anymore but instead raise the `Delx.StubbedDelegationError`. If you really
90 + Note that once you activate mocking all delegated functions do not return
91 + anymore but instead raise the `Delx.MockedDelegationError`. If you really
92 92 want to call the original implementation, you have to avoid any calls of
93 93 delegated functions.
94 94
  @@ -101,18 +101,18 @@ Register a mock for the `Delx.Delegator` behavior to your
101 101 `test/test_helper.exs` (or wherever you define your mocks):
102 102
103 103 ```elixir
104 - Mox.defmock(Delx.Delegator.Mock, for: Delx.Delegator)
104 + Mox.defmock(Greeter.DelegatorMock, for: Delx.Delegator)
105 105 ```
106 106
107 107 Then, in your `config/test.exs` you have to set the mock as delegator module
108 108 for your app.
109 109
110 110 ```elixir
111 - config :my_app, Delx, delegator: Delx.Delegator.Mock
111 + config :my_app, Delx, delegator: Greeter.DelegatorMock
112 112 ```
113 113
114 - Please make sure not to use the `:stub` option and a `:delegator` option at
115 - the same time as this may lead to unexpected behavior.
114 + Please make sure not to use the `:mock` option and a `:delegator` option at the
115 + same time as this may lead to unexpected behavior.
116 116
117 117 Now you are able to `expect` calls to delegated functions:
118 118
  @@ -127,7 +127,7 @@ defmodule GreeterTest do
127 127 describe "hello/1" do
128 128 test "delegate to Greeter.StringGreeter" do
129 129 expect(
130 - Delx.Delegator.Mock,
130 + Greeter.DelegatorMock,
131 131 :apply,
132 132 fn {Greeter, :hello},
133 133 {Greeter.StringGreeter, :hello},
  @@ -146,4 +146,24 @@ For more information on how to implement your own delegator, refer to the
146 146 docs of the `Delx.Delegator` behavior.
147 147
148 148 Note that the configuration is only applied at compile time, so you are unable
149 - to stub or replace the delegator module at runtime.
149 + to mock or replace the delegator module at runtime.
150 +
151 + ## Migration from v2 to v3
152 +
153 + Note that the function `defdel/2` has been removed in favor of `defdelegate/2`
154 + to give a better experience with the tooling. Additionally, let's say you want
155 + to migrate away from Delx you can simply un`use` Delx to fall back to the
156 + default `Kernel.defdelegate/2` and your code will still work.
157 +
158 + The config option to enable testing mode has changed from `stub` to `mock`. If
159 + you got the following line in your config:
160 +
161 + ```elixir
162 + config :greeter, Delx, stub: true
163 + ```
164 +
165 + Please change it to:
166 +
167 + ```elixir
168 + config :greeter, Delx, mock: true
169 + ```
  @@ -5,9 +5,9 @@
5 5 {<<"elixir">>,<<"~> 1.8">>}.
6 6 {<<"files">>,
7 7 [<<"lib">>,<<"lib/delx">>,<<"lib/delx/delegator.ex">>,
8 - <<"lib/delx/defdel.ex">>,<<"lib/delx/stubbed_delegation_error.ex">>,
9 - <<"lib/delx/delegator">>,<<"lib/delx/delegator/stub.ex">>,
10 - <<"lib/delx/delegator/common.ex">>,<<"lib/delx/test_assertions.ex">>,
8 + <<"lib/delx/mocked_delegation_error.ex">>,<<"lib/delx/delegator">>,
9 + <<"lib/delx/delegator/mock.ex">>,<<"lib/delx/delegator/common.ex">>,
10 + <<"lib/delx/test_assertions.ex">>,<<"lib/delx/defdelegate.ex">>,
11 11 <<"lib/delx.ex">>,<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,
12 12 <<"LICENSE">>]}.
13 13 {<<"licenses">>,[<<"MIT">>]}.
  @@ -15,4 +15,4 @@
15 15 [{<<"GitHub">>,<<"https://github.com/i22-digitalagentur/delx">>}]}.
16 16 {<<"name">>,<<"delx">>}.
17 17 {<<"requirements">>,[]}.
18 - {<<"version">>,<<"2.1.1">>}.
18 + {<<"version">>,<<"3.0.0">>}.
  @@ -13,13 +13,13 @@ defmodule Delx do
13 13 ...> end
14 14
15 15 You can delegate functions calls to another module by using the `Delx`
16 - module and calling the `Delx.Defdel.defdel/2` macro in the module body. It has
16 + module and calling the `defdelegate/2` macro in the module body. It has
17 17 the same API as Elixir's own `Kernel.defdelegate/2` macro.
18 18
19 19 iex> defmodule Greeter do
20 20 ...> use Delx, otp_app: :greeter
21 21
22 - ...> defdel hello(name), to: Greeter.StringGreeter
22 + ...> defdelegate hello(name), to: Greeter.StringGreeter
23 23 ...> end
24 24
25 25 iex> Greeter.hello("Tobi")
  @@ -40,10 +40,10 @@ defmodule Delx do
40 40
41 41 Delx brings it's own test assertions.
42 42
43 - All you need to do is to activate delegation stubbing for your test
43 + All you need to do is to activate delegation mocking for your test
44 44 environment by putting the following line in your `config/test.exs`:
45 45
46 - config :greeter, Delx, stub: true
46 + config :greeter, Delx, mock: true
47 47
48 48 Then in your tests, you can import `Delx.TestAssertions` and use the
49 49 `Delx.TestAssertions.assert_delegate/2` and
  @@ -61,8 +61,8 @@ defmodule Delx do
61 61 end
62 62 end
63 63
64 - Note that once you activate stubbing all delegated functions do not return
65 - anymore but instead raise the `Delx.StubbedDelegationError`. If you really
64 + Note that once you activate mocking all delegated functions do not return
65 + anymore but instead raise the `Delx.MockedDelegationError`. If you really
66 66 want to call the original implementation, you have to avoid any calls of
67 67 delegated functions.
68 68
  @@ -74,14 +74,14 @@ defmodule Delx do
74 74 Register a mock for the `Delx.Delegator` behavior to your
75 75 `test/test_helper.exs` (or wherever you define your mocks):
76 76
77 - Mox.defmock(Delx.Delegator.Mock, for: Delx.Delegator)
77 + Mox.defmock(Greeter.DelegatorMock, for: Delx.Delegator)
78 78
79 79 Then, in your `config/test.exs` you have to set the mock as delegator module
80 80 for your app.
81 81
82 - config :my_app, Delx, delegator: Delx.Delegator.Mock
82 + config :my_app, Delx, delegator: Greeter.DelegatorMock
83 83
84 - Please make sure not to use the `:stub` option and a `:delegator` option at
84 + Please make sure not to use the `:mock` option and a `:delegator` option at
85 85 the same time as this may lead to unexpected behavior.
86 86
87 87 Now you are able to `expect` calls to delegated functions:
  @@ -96,7 +96,7 @@ defmodule Delx do
96 96 describe "hello/1" do
97 97 test "delegate to Greeter.StringGreeter" do
98 98 expect(
99 - Delx.Delegator.Mock,
99 + Greeter.DelegatorMock,
100 100 :apply,
101 101 fn {Greeter, :hello},
102 102 {Greeter.StringGreeter, :hello},
  @@ -114,7 +114,7 @@ defmodule Delx do
114 114 docs of the `Delx.Delegator` behavior.
115 115
116 116 Note that the configuration is only applied at compile time, so you are unable
117 - to stub or replace the delegator module at runtime.
117 + to mock or replace the delegator module at runtime.
118 118 """
119 119
120 120 defmacro __using__(opts) do
  @@ -125,15 +125,16 @@ defmodule Delx do
125 125
126 126 config = Application.get_env(otp_app, Delx, [])
127 127
128 - case Keyword.fetch(config, :stub) do
128 + case Keyword.fetch(config, :mock) do
129 129 {:ok, true} ->
130 - @delegator Delx.Delegator.Stub
130 + @delegator Delx.Delegator.Mock
131 131
132 132 _ ->
133 133 @delegator Keyword.get(config, :delegator, Delx.Delegator.Common)
134 134 end
135 135
136 - import Delx.Defdel
136 + import Kernel, except: [defdelegate: 2]
137 + import Delx.Defdelegate
137 138 end
138 139 end
139 140 end
  @@ -1,46 +0,0 @@
1 - defmodule Delx.Defdel do
2 - @moduledoc """
3 - A module defining a macro to define delegate functions.
4 - """
5 -
6 - @doc """
7 - You can delegate functions calls to another module by using the `Delx`
8 - module and calling the `defdel/2` macro in the module body. It has
9 - the same API as Elixir's own `Kernel.defdelegate/2` macro.
10 -
11 - ## Example
12 -
13 - Before calling `defdel/2`, you need to use `Delx`.
14 -
15 - iex> defmodule Greeter do
16 - ...> use Delx, otp_app: :greeter
17 -
18 - ...> defdel hello(name), to: Greeter.StringGreeter, as: :welcome
19 - ...> end
20 - """
21 - defmacro defdel(funs, opts) do
22 - funs = Macro.escape(funs, unquote: true)
23 -
24 - quote bind_quoted: [funs: funs, opts: opts] do
25 - target =
26 - opts[:to] || raise ArgumentError, "expected to: to be given as argument"
27 -
28 - for fun <- List.wrap(funs) do
29 - {name, args, as, as_args} = Kernel.Utils.defdelegate(fun, opts)
30 -
31 - # Dialyzer may possibly complain about "No local return". So we tell him
32 - # to stop as we're only delegating here.
33 - @dialyzer {:nowarn_function, [{name, length(as_args)}]}
34 -
35 - @doc delegate_to: {target, as, length(as_args)}
36 - def unquote(name)(unquote_splicing(args)) do
37 - @delegator.apply(
38 - {unquote(__MODULE__), unquote(name)},
39 - {unquote(target), unquote(as)},
40 - unquote(as_args)
41 - )
42 - end
43 - end
44 - end
45 - end
46 - end
  @@ -0,0 +1,46 @@
1 + defmodule Delx.Defdelegate do
2 + @moduledoc """
3 + A module defining a macro to define delegate functions.
4 + """
5 +
6 + @doc """
7 + You can delegate functions calls to another module by using the `Delx`
8 + module and calling the `defdelegate/2` macro in the module body. It has
9 + the same API as Elixir's own `Kernel.defdelegate/2` macro.
10 +
11 + ## Example
12 +
13 + Before calling `defdelegate/2`, you need to use `Delx`.
14 +
15 + iex> defmodule Greeter do
16 + ...> use Delx, otp_app: :greeter
17 +
18 + ...> defdelegate hello(name), to: Greeter.StringGreeter, as: :welcome
19 + ...> end
20 + """
21 + defmacro defdelegate(funs, opts) do
22 + funs = Macro.escape(funs, unquote: true)
23 +
24 + quote bind_quoted: [funs: funs, opts: opts] do
25 + target =
26 + opts[:to] || raise ArgumentError, "expected to: to be given as argument"
27 +
28 + for fun <- List.wrap(funs) do
29 + {name, args, as, as_args} = Kernel.Utils.defdelegate(fun, opts)
30 +
31 + # Dialyzer may possibly complain about "No local return". So we tell him
32 + # to stop as we're only delegating here.
33 + @dialyzer {:nowarn_function, [{name, length(as_args)}]}
34 +
35 + @doc delegate_to: {target, as, length(as_args)}
36 + def unquote(name)(unquote_splicing(args)) do
37 + @delegator.apply(
38 + {unquote(__MODULE__), unquote(name)},
39 + {unquote(target), unquote(as)},
40 + unquote(as_args)
41 + )
42 + end
43 + end
44 + end
45 + end
46 + end
Loading more files…