Aaron Z
Aaron Z

Reputation: 358

Elixir Postgres view returning empty dataset when testing

I am trying to test a view created in Postgres, but it is returning an empty result set. However, when testing out the view in an Elixir interactive shell, I get back the expected data. Here are the steps I have taken to create and test the view:

  1. Create a migration:
 def up do
   execute """
     CREATE VIEW example_view AS
     ...
  1. Create the schema:
  import Ecto.Changeset

  schema "test_view" do
   field(:user_id, :string)
  1. Test:
  describe "example loads" do
   setup [
     :with_example_data
   ]

   test "view" do
     query = from(ev in Schema.ExampleView)
     IO.inspect Repo.all(query)
   end
 end

The response back is an empty array []

Is there a setting that I am missing to allow for views to be tested in test?

Upvotes: 0

Views: 449

Answers (1)

sabiwara
sabiwara

Reputation: 3204

As pointed out in one of the comments:

  • iex, mix phx.server... run on the :dev environment and the dev DB
  • tests use the :test environment and runs on a separate DB

It actually makes a lot of sense because you want your test suite to be reproducible and independent of whatever records that you might create/edit in your dev env.

You can open iex in the :test environment to confirm that your query returns the empty array here too:

MIX_ENV=test iex -S mix

What you'll need is to populate your test DB with some known records before querying. There are at least 2 ways to achieve that: fixtures and seeds.

  1. Fixtures:
  • define some helper functions to create records in test/support/test_helpers.ex (typically: takes some attrs, adds some defaults and calls some create_ function from your context)
  def foo_fixture(attrs \\ %{}) do
    {:ok, foo} =
      attrs
      |> Enum.into(%{name: "foo", bar: " default bar"})
      |> MyContext.create_foo()

    foo
  end
  • call them within your setup function or test case before querying
  • side note: you should use DataCase for tests involving the DB. With DataCase, each test is wrapped in its own transaction and any fixture that you created will be rollback-ed at the end of the test, so tests are isolated and independent from each other.
  1. Seeds:
  • If you want to include some "long-lasting" records as part of your "default state" (e.g. for a list of countries, categories...), you could define some seeds in priv/repo/seeds.exs.
  • The file should have been created by the phoenix generator and indicate you how to add seeds (typically use Repo.insert!/1)
  • By default, mix will run those seeds whenever you run mix ecto.setup or mix ecto.reset just after your migrations (whatever the env used)
  • To apply any changes in seeds.exs, you can run the following:
# reset dev DB
mix ecto.reset
# reset test DB
MIX_ENV=test mix ecto.reset
  • If you need some seeds to be environment specific, you can always introduce different seed files (e.g. dev_seeds.exs) and modify your mix.exs to configure ecto.setup.
  • Seeds can be very helpful not only for tests but for dev/staging in the early stage of a project, while you are still tinkering a lot with your schema and you are dropping the DB frequently.

I usually find myself using a mix of both approaches.

Upvotes: 1

Related Questions