Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions config/test.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
use Mix.Config

config :example, service: Example.MockService
24 changes: 3 additions & 21 deletions lib/example/worker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ defmodule Example.Worker do

alias Example.DefaultService

# When using ElixirLS, defining the service at compile time will result in an
# error because ElixirLS always compiles using MIX_ENV=test which mean @service
# will always be set to MockService, which does not have `foo/0`
# @service Application.get_env(:example, :service, DefaultService)
# @service DefaultService

def service() do
def service do
Application.get_env(:example, :service, DefaultService)
end

Expand All @@ -23,24 +17,12 @@ defmodule Example.Worker do

def init(_init_arg) do
initial_state = "no foo for you"

{:ok, initial_state, {:continue, :get_foo_from_service}}
end

def handle_continue(:get_foo_from_service, _state) do
# And here lies the problem. We want to call our service to get
# whatever inital state it provides, but in doing so, we break
# in the test environment because the MockService doesn't have
# a function called `foo/0` until it can be defined in the expects
# block within the test - by that time, this code has already
# been executed because this GenServer is part of the staticly
# defined supervision tree in `application.ex`.

value_of_foo =
if function_exported?(service(), :foo, 0) do
service().foo()
else
"#{inspect(service())} does not support foo"
end
value_of_foo = service().foo()

{:noreply, value_of_foo}
end
Expand Down
11 changes: 0 additions & 11 deletions test/support/mock_service.ex

This file was deleted.

7 changes: 7 additions & 0 deletions test/support/test1_example.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Test1Service do
@behaviour Example.ServiceBehaviour

def foo() do
"test 1 says foo"
end
end
7 changes: 7 additions & 0 deletions test/support/test2_example.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Test2Service do
@behaviour Example.ServiceBehaviour

def foo() do
"test 2 says moo"
end
end
31 changes: 14 additions & 17 deletions test/worker_test.exs
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
defmodule Example.WorkerTest do
use ExUnit.Case
import Mox
alias Example.Worker

describe "default service" do
test "returns default service foo" do
assert Worker.get_foo() =~ ~s(default says foo)
end
# In order to have the Worker use the test services we need to restart
# the process; killing it will suffice as it is a supervised process
def restart_worker() do
pid = Process.whereis(Worker)
Process.exit(pid, :kill)
Process.sleep(10)
end

describe "mocked service" do
setup do
# Normally you would add this to `test_helper.ex`, or `support/mocks.ex
Mox.defmock(Example.MockService, for: Example.ServiceBehaviour)
test "returns mocked service foo" do
Application.put_env(:example, :service, Test1Service)

Example.MockService
|> expect(:foo, fn -> "setup all says foo" end)
restart_worker()

:ok
assert Worker.get_foo() =~ ~s(test 1 says foo)
end

setup :verify_on_exit!
test "returns mocked service moo" do
Application.put_env(:example, :service, Test2Service)

test "returns mocked service foo" do
Example.MockService
|> expect(:foo, fn -> "mock says foo" end)
|> allow(self(), Process.whereis(Worker))
restart_worker()

assert Worker.get_foo() =~ ~s(mock says foo)
assert Worker.get_foo() =~ ~s(test 2 says moo)
end
end
end