loading...
Cover image for How to dynamically load configurations for tests at runtime within Elixir libraries

How to dynamically load configurations for tests at runtime within Elixir libraries

alexjuca profile image Alexandre Antonio Juca ・2 min read

I recently started working with elixir and had the opportunity to create a library at Next Business Solutions called ExOktaAuth that enables elixir applications to handle signup/sign-in flows using Okta's OAuth 2.0/OIDC service.

Now while writing tests for the library, I faced an issue while trying to test a function that was dependent on application configuration that is usually defined in the config.ex file of the phoenix application that is using the library as a dependency.

This is a snippet of the functions code:

config = :ex_okta_auth
             |> Application.fetch_env!(__MODULE__)
             |> validate_config!(:client_id)
             |> validate_config!(:client_secret)
             |> validate_config!(:site)
             |> validate_config!(:redirect_uri)


    site = Keyword.get(config, :site)
    ExOAuth2.Client.new([
      strategy: __MODULE__,
      client_id: Keyword.get(config, :client_id),
      client_secret: Keyword.get(config, :client_secret),
      site: site,
      redirect_uri: Keyword.get(config, :redirect_uri),
      authorize_url: site <> "/v1/authorize",
      token_url: site <> "/v1/token"
    ])
    |> ExOAuth2.Client.put_serializer("application/json", Jason)

Essentially what this code does is load and validate configuration options that it acquires from the application's config.ex file and uses that to create an %ExOAuth2.Client struct that is responsible for setting up the definitions used for interactions with okta's API.

This works all good and well but implementing a unit test for this function turned out to be quite difficult for me since I am new to elixir.

Since the function was dependent on the configuration, I had to find a way to load a specific configuration at runtime so the function could acquire those configuration options during testing.

I came up with the following solution.

Step 1: Define configuration to load during test

Create a file named config.ex in the test/ folder of your library.

import Config

config :ex_okta_auth, ExOktaAuth.Okta,
    client_id: "isoaspoaisa",
    client_secret: "kajskaljs",
    site: "http://127.0.0.1:4000/default",
    redirect_uri: "https://your-apps-callback-uri"

Step 2: Load config dynamically during tests

Config.Reader.read!("test/config.ex")
|> Application.put_all_env()

Here you can see how I used this solution in the context of a real test.

defmodule ExOktaAuthTest do
  use ExUnit.Case
  doctest ExOktaAuth

  setup_all do
    setup_config()
    {:ok, state: :ok}
  end

  def setup_config() do
    Config.Reader.read!("test/config.ex")
    |> Application.put_all_env()
  end

  test "Should return a valid client" do
    assert ExOktaAuth.Okta.client == Helpers.valid_client
  end
end

I would love to know if there is a better solution for this problem and if my solution has any pitfalls, so please do critique and provide feedback.

This was a post from Alexandre Juca, A software Engineer working at a wonderful company called Next Solutions based in Luanda/Angola.

Discussion

markdown guide