# FakeServer
[](https://travis-ci.org/bernardolins/fake_server)
[](https://coveralls.io/github/bernardolins/fake_server?branch=master)
[](http://inch-ci.org/github/bernardolins/fake_server)
FakeServer is a simple Elixir library that helps you to mock web requests.
## Installation
FakeServer is available on [Hex](https://hex.pm/packages/fake_server). To use it on your application, just add it to `mix.exs` as a test dependency.
```elixir
def deps do
[{:fake_server, "~> 0.5.0", only: :test}]
end
```
## How it works
First, you create some `FakeServer.Status`. Those status are the way the server will respond when a request arrives. In a status you specify the response code and body. You can add some headers to the response as well.
```elixir
iex(1)> FakeServer.Status.create(:status200, %{response_code: 200, response_body: "Hello World"})
:ok
iex(2)> FakeServer.Status.create(:status400, %{response_code: 400, response_body: "bad_request"})
:ok
iex(3)> FakeServer.Status.create(:status500, %{response_code: 500, response_body: "internal_server_error"})
:ok
```
*Multiple servers can use the same status, so you just need to define it once.*
Then, you create a server that uses some of the statuses available:
```elixir
iex(4)> FakeServer.run(:server_name, [:status200, :status500, :status400])
{:ok, "127.0.0.1:8259"}
```
Now you have an HTTP server running; You can access the server using the address returned by `FakeServer.run/2` function. This new server will respond with the status specified in the list you provided. The first request will get the first status as a response, and so on. When the server responds with a status, it is removed from the list and the server will respond with the next status.
```bash
$ curl 127.0.0.1:8259
Hello World
$ curl 127.0.0.1:8259
internal_server_error
$ curl 127.0.0.1:8259
bad_request
```
If the list empties, the request will get a default response:
```bash
$ curl 127.0.0.1:8259
"status": "no more actions"
```
## Using it on your tests
The primary use of FakeServer is on tests. It can simplify some complex to test scenarios, like timeouts, external servers instability, cache usage, and many others. Just be creative :)
Here are some usage examples:
**Important:** From version *0.2.1* to *0.3.0*, `FakeServer.Server` was replaced by `FakeServer`
```elixir
### test/test_helper.exs
ExUnit.start()
# create some status that your external server could respond with
# you just need to do it once for you entire test suite.
FakeServer.Status.create(:status200, %{response_code: 200, response_body: ~s<"username": "mr_user">})
FakeServer.Status.create(:status500, %{response_code: 500, response_body: ~s<"error": "internal server error">})
FakeServer.Status.create(:status403, %{response_code: 403, response_body: ~s<"error": "forbidden">})
# you can also pass `response_headers` (optional):
FakeServer.Status.create(:status404, %{response_code: 404, response_body: ~s<"error": "not found">, response_headers: %{"Content-Length": 5}})
### test/user_test.exs
defmodule UserTest do
use ExUnit.Case
setup_all do
# you can run a single server on a test file
# start a fake server with an empty status_list
# you can ignore the third param if you want the server to run on a random port
# when using a global server, make sure :async option is set to false on ExUnit
{:ok, address} = FakeServer.run(:external_server, [], %{port: 5000})
# point your application to the new fake server
System.put_env(:external_server_url, address)
# you can use ExUnit callback to stop the server
on_exit fn ->
FakeServer.stop(:external_server)
end
end
test "#get returns user if the external server responds 200" do
# If you created a global server, you just need to modify the server behavior on each test case
# just add the status sequence you want the server to return
FakeServer.modify_behavior(:external_server, :status200)
# make the request to the fake server and validate it works
assert User.get == %{username: "mr_user"}
end
test "#get retry up to 3 times when external server responds with 500" do
FakeServer.modify_behavior(:external_server, [:status500, :status500, :status500, :status200])
# in our application, one User.get call makes multiple requests to the server when it returns 500
assert User.get == %{username: "mr_user"}
end
test "#get returns timeout after 3 retries" do
# another retry example, this time with a timeout scenario
FakeServer.modify_behavior(:external_server, [:status500, :status500, :status500, :status500])
assert User.get == %{error: "timeout", code: 408}
end
test "#get serves stale content when external server is down if there is some cache available" do
FakeServer.modify_behavior(:external_server, [:status200, :status500])
# our application saves cache on the first successfull response
# so we make a get request with a 200 response from fake server to save some cache
User.get
# the second response from fake server is 500, but since there's some cache, the response is correct
# that's how we know the cache is working
assert User.get == %{username: "mr_user"}
end
end
```
## Documentation
Detailed documentation is available on [Hexdocs](https://hexdocs.pm/fake_server/api-reference.html)