Using Ecto Sandbox for Test Isolation and Concurrency

We mentioned that DataCase uses some aliases, imports, and macros to give us the functionality our tests need. One of the features that file provides is the Ecto Sandbox. The role of the sandbox is to undo all changes we have done to the database during our tests. These database transaction rollbacks give us test isolation.

The way the sandbox operates is quite efficient too: instead of deleting all of the data once the suite finishes, which would be expensive, it just wraps each test in a transaction. Once the test is done, the transaction is rolled back and everything behaves as if the data was never there.

While a database sandbox is commonplace in many web frameworks or database libraries, what sets the Ecto Sandbox apart is that it enables concurrent testing within the same database. In other words, you can run multiple tests that interact with the database at the same time, and they won’t affect each other. This is a big deal since most developers must make compromises between slow tests that sequentially hit the DB and “fast” tests that stub out all DB calls altogether. With the Ecto Sandbox, we can make full use of the database and still use all of our machine resources, making sure the test suite runs as fast as it possibly can. We can do all of this without having to manage multiple database instances.

Note, however, that tests do not run concurrently by default. In order to enable concurrency, we need to pass the async: true true option when using Rumbl.DataCase, which is exactly what we have done in both AccountsTest and MultimediaTest:

 defmodule​ Rumbl.AccountsTest ​do
 use​ Rumbl.DataCase, ​async:​ true

Then back in Rumbl.DataCase, Phoenix defines a setup block that configures the sandbox for us:

1: setup tags ​do
2: :ok​ = Ecto.Adapters.SQL.Sandbox.checkout(Rumbl.Repo)
3: 
4: unless​ tags[​:async​] ​do
5:  Ecto.Adapters.SQL.Sandbox.mode(Rumbl.Repo, {​:shared​, self()})
6: end
7: 
8: :ok
9: end

On line 2, we check out a connection from the sandbox. The sandbox wraps the connection in a transaction which is automatically rolled back at the end of the test. Then we check if the test is running asynchronously. If the test is not asynchronous, we make sure the connection is shared across all processes on line 5. We are going to see a use case for sharing the connection in Chapter 13, Testing Channels and OTP.

You can find out more about how the sandbox works by checking out the Hex documentation.[24] Now let’s move on to views and controllers.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.164.34