vendredi 31 mars 2017

Unit testing elixir functions properly

I'm fairly new to elixir and functional programming in general and I'm struggling to properly unit test functions that are composed of other functions. The general question is: when I have a function f that uses other functions g, h... internally, which approach should I take to test the whole?

Coming from the OOP world the first approach that comes to mind involves injecting the functions f depends of. I could unit test g, h... and inject all of those as arguments to f. Then, unit tests for f would just make sure it calls the injected functions as expected. This feels like overfitting though, and as an overall cumbersome approach that is against the functional mindset for which function composition should be a cheap thing to do and you should not be concerning yourself on passing all those arguments around the whole codebase.

I can also unit test g, h... as well as f by treating each of those as black boxes, which feels like the appropriate thing to do, but then the complexity of f's tests increases dramatically. Having simple tests that scale is one of the main purposes of unit testing.

To make the argument more concrete I'll put an example of a function that composes other functions inside and that I don't know how to unit test properly. This in particular is code for a plug that handles the creation of a resource in a RESTful fashion. Note that some of the "dependencies" are pure functions (such as validate_account_admin) but others are not (Providers.create):

  def call(conn, _opts) do
    account_uuid = conn.assigns.current_user.account["uuid"]

    with {:ok, conn}      <- Http.Authorization.validate_account_admin(conn),
         {:ok, form_data} <- Http.coerce_form_data(conn, FormData),
         {:ok, provider}  <- Providers.create(FormData.to_provider(form_data), account_uuid: account_uuid) do
      Http.respond_create(conn, Http.provider_path(provider))
    else
      {:error, reason, messages} -> Http.handle_error(conn, reason, messages)
    end
  end

Thanks!

Aucun commentaire:

Enregistrer un commentaire