Nesting CaseTemplates?

I’m not quite sure if nesting is the right expression here, but basically I’m looking to define a parent CaseTemplate that then my individual DataCase and ConnCase modules can depend on.

My original idea was to do this:

defmodule MyApp.CaseTemplate do
  use ExUnit.CaseTemplate

  setup _tags do
    # do stuff
    :ok
  end
end

defmodule MyApp.DataCase do
  use MyApp.CaseTemplate
end

And then I would expect any test using MyApp.DataCase to run the setup block defined in MyApp.CaseTemplate. But it fails with this error:

== Compilation error in file test/support/data_case.ex ==
** (RuntimeError) cannot use ExUnit.Case without starting the ExUnit application, please call ExUnit.start() or explicitly start the :ex_unit app

Just in case there is a better way to achieve my goal, let me share what I was trying to achieve in the first place.

defmodule MyApp.MyTest do
  use MyApp.DataCase, async: true
  use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney

I would like to turn the above into this:

defmodule MyApp.MyTest do
  use MyApp.DataCase, async: true, vcr: true

And I want it to work for DataCase, ConnCase, and any others (without copying the setup code over).

Instead of a “parent” CaseTemplate you can create a normal module with functions. Then both DataCase as well as ConnCase can import that module and do setup :imported_function_name. This works exactly the same as setup callbacks in actual test modules.

2 Likes

That’s so clever and clean, thanks!

Now I realize I left off an important question in my original post – how do I call use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney? Is that something that can go into a setup function? I want this to happen whenever I pass vcr: true to use MyApp.DataCase.

That needs metaprogramming, so it’s likely the easiest to jut copy it into both case templates using/0.

Gotcha, thanks!