fake_server v2.1.0 FakeServer.ResponseFactory

Create reusable and customizable answers for your servers.

With response factories it is possible to create a default format of a given response and identify it with a name so that it can be shared across several test cases.

They are inspired by the ExMachina's factories, and were created to suit the use case where it is necessary to modify both the body or headers of a given response while testing different scenarios.

What is a factory?

A factory is just a function with no arguments inside a module that use FakeServer.ResponseFactory.

The function name must end in _response and it must return a FakeServer.Response structure. The factory name is everything before _response.

# test/support/my_response_factory.ex
defmodule MyResponseFactory do
  use FakeServer.ResponseFactory

  def person_response do
    ok(%{
      name: Faker.Name.name,
      email: Faker.Internet.free_email,
      company: %{name: Faker.Company.name, county: Faker.Address.country}
    }, %{"Content-Type" => "application/json"})
  end
end

Using a factory

To use a factory, just call ResponseFactory.build(:factory_name). This macro accepts two optinal arguments:

  • body_opts: This is a list with keys whose values should be overwritten in the body of factory's response. If any of the keys is set to nil, it will be deleted from the original body. If a key that does not exist on the original body is set here, it will be ignored.

  • header_opts: This is a map with the headers whose values should be overwritten. If any of the headers is set to nil, it will be deleted from the original header list. If a key that does not exist on the original header list is set here, it will be included on the headers list.

You can also create a list of responses with MyResponseFactory.build_list(list_size, :factory_name).

Example

# test/my_app/some_test.exs
defmodule MyApp.SomeTest do
  use ExUnit.Case, async: false
  import FakeServer

  test_with_server "basic factory usage" do
    customized_response = %{body: body} = MyResponseFactory.build(:person)
    person = Poison.decode!(body)

    route "/person", customized_response

    response = HTTPoison.get! FakeServer.address <> "/person"
    body = Poison.decode!(response.body)

    assert response.status_code == 200
    assert person["name"] == body["name"]
    assert person["email"] == body["email"]
    assert person["company"]["name"] == body["company"]["name"]
    assert person["company"]["country"] == body["company"]["country"]
  end

  test_with_server "setting custom attributes" do
    route "/person", do: MyResponseFactory.build(:person, name: "John", email: "john@myawesomemail.com")
    person = Poison.decode!(body)

    response = HTTPoison.get! FakeServer.address <> "/person"
    body = Poison.decode!(response.body)

    assert response.status_code == 200
    assert body["name"] == "John"
    assert body["email"] == "john@myawesomemail.com"
  end

  test_with_server "deleting an attribute" do
    route "/person", do: MyResponseFactory.build(:person, name: nil)

    response = HTTPoison.get! FakeServer.address <> "/person"
    body = Poison.decode!(response.body)

    assert response.status_code == 200
    assert body["name"] == nil
  end

  test_with_server "overriding a header" do
    route "/person", do: MyResponseFactory.build(:person, %{"Content-Type" => "application/x-www-form-urlencoded"})

    response = HTTPoison.get! FakeServer.address <> "/person"

    assert response.status_code == 200
    assert Enum.any?(response.headers, fn(header) -> header == {"Content-Type", "application/x-www-form-urlencoded"} end)
  end

  test_with_server "deleting a header" do
    route "/person", do: MyResponseFactory.build(:person, %{"Content-Type" => nil})

    response = HTTPoison.get! FakeServer.address <> "/person"

    assert response.status_code == 200
    refute Enum.any?(response.headers, fn(header) -> header == {"Content-Type", _} end)
  end

  test_with_server "create a list of responses" do
    person_list = MyResponseFactory.build_list(3, :person)

    route "/person", do: person_list

    Enum.each(person_list, fn(person) ->
      response = HTTPoison.get! FakeServer.address <> "/person"
      body = Poison.decode!(response.body)

      assert response.status_code == 200
      assert person.body[:name] == body["name"]
      assert person.body[:email] == body["email"]
      assert person.body[:company][:name] == body["company"]["name"]
      assert person.body[:company][:country] == body["company"]["country"]
    end)
  end
end