Best practice for stubbing

I think the solution is very context dependent. Here’s a few solutions in the order I would try them:

Just use the backend

Assuming you control the backend (is the Elm app served by the backend?) you should be able to create a user in your local dev system and use that without making any changes to the Elm code. This is by far the simplest solution and the one I go for first when developing Elm apps.

Pros:

  • Simple
  • You’re probably already running a local server if the backend hosts the Elm app
  • Don’t need to change Elm code
  • Making real (local) HTTP requests so you’re using the full stack

Cons:

  • You need to control the backend
  • You need to run a local server

Fake the backend

If you’re developing against a third-party service, I like to create a small fake app that I’ll run locally that responds to the same API but returns canned responses. I’ve used this technique a lot when integrating backends with third-party services that don’t have a sandbox.

Pros

  • Don’t need to change Elm code
  • Making real (local) HTTP requests so you’re using the full stack

Cons

  • You need to run a local server
  • You need to write a fake service

Conditional in the Elm code

Given the following types:

type alias Stubbable a
  = Hardcoded a
  | GetFromApi

type alias Config =
  { user : Stubbable User
  }

type alias Model =
  { config : Config
  , currentUser : User
  }

you’d probably build up the the Config record based on flags passed into the app. Then you could write this task-based approach for switching:

fetchUser : Config -> Int -> Cmd Msg
fetchUser config id =
  case config.user of
    Hardcoded user ->
      Task.attempt UserFetched (fetchHardcodedUser user)

    GetFromApi ->
      Task.attempt UserFetched (fetchUserFromApi id)

fetchUserFromApi : Int -> Task Http.Error User
fetchuserFromApi id =
  Http.get ("http://someservice.com/user/" ++ id) userDecoder
    |> Http.toTask

fetchHardcodedUser : User -> Task a User
fetchHardcodedUser user =
  Task.succeed user

Pros

  • More fine-grained control
  • Don’t need to run a local server

Cons

  • Need to change the Elm code
  • Doesn’t exercise the full stack (HTTP could be unimplemented and it would still “work on my machine”)
2 Likes