Writing doctests when a struct is returned

405 Views Asked by At

An answer to a similar question has this question.

In order to test a function with doctests, you must be able to predict the output of your function.

Issue

As mentioned in the title I would like to stick with using doctests but this doesn't seem to be working and I don't believe there isn't a way to do it.

Code

  @doc """
  Update a field(s) in a setting record

  ## Examples

      iex> example = Setting.get(id: 4)
      iex> Setting.update(example, %{keyname: "an_example"})
      {:ok, %Elements.Setting{_}}


  """
  @spec update(struct :: Elements.Setting, changes :: map()) :: {:ok, Ecto.Schema} | {:error, Ecto.Changeset.t()}
  def update(struct, changes) do
    ...
  end

Above is the code that I've been trying and variations of it. Such as using _ where the data is going to be unexpected. Just the bits that wouldn't have changed.

For example, ideally I would want the return value to look like {:ok, %Elements.Setting{keyname: "an_example", _}. So the documentation passes but it's also legible to users what they are reading and can see the effects of the code that was before it.

iex

iex(6)> Setting.update(example, %{keyname: "an_example"})
{:ok,
 %Elements.Setting{
   __meta__: #Ecto.Schema.Metadata<:loaded, "settings">,
   children: #Ecto.Association.NotLoaded<association :children is not loaded>,
   id: 4,
   inserted_at: ~N[2018-08-17 07:53:23.000000],
   keyname: "an_example",
   name: "Display Breadcrumb",
   parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
   parent_id: 2,
   updated_at: ~N[2018-08-17 10:29:46.707878]
 }}

Based of the quoted answer at the start you can probably notice that at the very least the inserted_at: ... and updated_at: ... are going to be different meaning the test will always fail.

Is there anything that can be done or even any workaround?

1

There are 1 best solutions below

4
On

You should put the documentation on what %Elements.Setting{} is to where it belongs (the module that defines this struct,) and stick to matching what you just explicitly set:

iex> example = Setting.get(id: 4)
iex> with {:ok, %Setting{} = result} <- Setting.update(example, %{keyname: "an_example"}),
...>   do: result.keyname == "an_example"
true

The values you want to show are test-specific and very misleading for anybody who is supposed to read the documentation.