elixirphoenix-frameworkectopostgrex

Allow Ecto queries to run immediately in a test environment?


I'd like to write tests to validate that the SQL queries in my application return data adhering to certain constraints: namely, that return values are presented in descending insertion order. In the application, I'm using timestamps() in my schemas to include an inserted_at field to the DB, and querying against it in my queries (SELECT … ORDER BY inserted_at DESC).

My trouble comes in my tests: if I have test code like

person1_params = %{name: "Tidehunter"}
{:ok, tidehunter} = People.create_person(person1_params)

person2_params = %{name: "Kunkka"}
{:ok, kunkka} = People.create_person(person2_params)

person3_params = %{name: "Windrunner"}
{:ok, windrunner} = People.create_person(person3_params)

and I'd like to assert on their order, like

people = People.get_in_order_of_recency()
assert Enum.at(people, 0).name == "Windrunner"

this fails, even though in manual tests it all appears to work. Upon inspection, I see that inserted_at for all three records is identical. I've tried adding :timer.sleep() calls, but it doesn't change the outcome, suggesting some batching or laziness at the Ecto/Postgrex layer.

The "simplest" solution I could think of would be some way to "force" a transaction to occur at the call site, so I could :timer.sleep(1) between them, giving me distinct inserted_at fields (thus the question title) but at the risk of XY problem I'm open to other suggestions. Thanks!


Solution

  • Since it seems that you are trying to test the get_in_order_of_recency method as opposed to the datetime features of your database/ecto, you could alias <MYPROJ>.Repo and then do something like:

    Repo.insert!(%People{inserted_at: ~N[2019-01-01 00:00:10], name: "Tidehunter"})
    Repo.insert!(%People{inserted_at: ~N[2019-01-01 00:00:11], name: "Kunkka"})
    Repo.insert!(%People{inserted_at: ~N[2019-01-01 00:00:12], name: "Windrunner"})
    

    In your test instead of using the create interface. Which would allow you to verify that your method is correctly retrieving the people in the order you want.

    As an alternative, consider the test failure legitimate. Your desired ordering is not maintained when multiple records are introduced simultaneously. As a remedy add the id as a second column to order by in descending order which will enforce the order you're looking for.