ECTO Starting In Test Environment

Hi,
I am learning elixir and am a relative noob so this might seem basic - hope so :slight_smile:

I am writing a package which is primarily a group of plugs which may or may not get used within phoenix, but I donā€™t want phoenix as a dependency.

However, one of the plugs which is optional, uses ecto.

This ecto plug may or may not get used by the developer so again, I dont want it as a hard dependency for the package but as a test dependency so that I can prove that the plug is building the query correctly.

I asked on the phoenix forum about mocking ecto and testing its generated queries but a few people advised against it and said to use ex_machina and go to the DB instead, so this is the strategy I have taken.

But, in my test, when I try and insert something into the repo, it comes back with this error :-

      ** (ArgumentError) argument error
    (stdlib) :ets.lookup(MyPlugs.Repo.Pool, #PID<0.1616.0>)
    (db_connection) lib/db_connection/ownership/manager.ex:53: DBConnection.Ownership.Manager.lookup/2
    (db_connection) lib/db_connection/ownership.ex:120: DBConnection.Ownership.checkout/2
    (db_connection) lib/db_connection.ex:716: DBConnection.checkout/2
    (db_connection) lib/db_connection.ex:623: DBConnection.run/3
    (db_connection) lib/db_connection.ex:671: DBConnection.transaction/3
    (espec) lib/espec/example_runner.ex:67: ESpec.ExampleRunner.try_run/3
    (espec) lib/espec/example_runner.ex:39: ESpec.ExampleRunner.run_example/2

I am thinking that this is because the repo (MyPlugs.Repo) isnā€™t started ? When I look at a phoenix app, it does :-

children = [
      # Start the endpoint when the application starts
      supervisor(Products.Endpoint, []),
      # Start the Ecto repository
      supervisor(Products.Repo, []),
      # Here you could define other workers and supervisors as children
      # worker(Products.Worker, [arg1, arg2, arg3]),
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Products.Supervisor]
    Supervisor.start_link(children, opts)

but in my case, I do not really have an ā€œapplicationā€ to put this code in (or do I and I just dont know it ?) as the package is just a set of plugs. Please excuse my ignorance on this one, I havenā€™t ventured into the world of supervised apps yet - I only have a basic understanding of them.

Assuming this is the problem, does anyone know how I can start my repo ? Or does anyone know the real cause of that error if I have assumed wrong ?

Thanks

Gary

1 Like

Every single Elixir ā€˜thingā€™ (App, Library, etcā€¦) should have an entrance Application (even if empty) as it is often required for release managment. The mix new should create it for you if I recall correctly. Also your dependencies that you want to test against should be a dependency at :test time even if they are not at release time via something like:

      {:credo, "~> 0.3", only: [:dev, :test]},

The only: key means that the dependency is required for development and testing, but it is not required for end-user usage.

Thanks :slight_smile:
Ive now setup the application to start the applicationā€™s repo but still the same issue.
This is the code I added to the existing application file (which was empty as added by mix new)

  use Application

  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    children = [
      # Start the Ecto repository
      supervisor(MyPlugs.Repo, []),
      # Here you could define other workers and supervisors as children
      # worker(Products.Worker, [arg1, arg2, arg3]),
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: MyPlugs.Supervisor]
    Supervisor.start_link(children, opts)
  end

maybe my assumption about the repo being started is not correct. any ideas ?

Ive worked it out - just adding

MyPlugs.Repo.start_link

to the test helper worked a treat.

Thanks for your help

1 Like

I do not think that testing loads the applications (and you may not want to load your repo unless it should be loaded in users as well). Rather the Ecto line Ecto.Adapters.SQL.Sandbox.mode(MyServer.Repo, :manual) in your test_helper.exs file should set that up for your testing (in sandbox mode so no saving stuff).

mix test task starts the application. The repo should be started first, before the sandbox mode can be selected. Calling Repo.start_link in test_helper.exs is the correct approach. Ecto uses it frequently in the integration test suite: https://github.com/elixir-ecto/ecto/blob/master/integration_test/pg/test_helper.exs#L74

It might be desired to also call Adapter.ensure_all_started(Repo, :temporary) to start all dependent applications.

3 Likes

Just out of curiosity (as Iā€™m also new to Elixir/learing Elixir).

Why it is required to explicitly start the Repo even though the supervisor of the Repo is already started during application load (in the entry .ex file of the application)?

Thanks