In this post, I will try to explain how to do integration tests for your Phoenix project and add them to the checks in your repository
These are the tools that we will use:
- Ex_machina to create test data.
- Wallaby to test your web applications by simulating realistic user interactions.
- GitHub Actions to configure the environment and run the tests at GitHub.
ExMachina
The first step will be to configure your project to easily create test data. As mentioned above, we will use ex_machina
. To install it follow the instructions of their repository. Once we have installed the library, let's configure it to our needs.
Factories and Factory Module
We will split factories into separate files and will import them by creating a Factory module.
Here we have the code of our Client
factory.
# test/suport/factories/client.ex defmodule OurProject.ClientFactory do defmacro __using__(_opts) do quote do def client_factory do %OurProject.Clients.Client{ name: "Client Name", contact_info: "Client contact_info" } end end end end
And then we import it in our Factory Module.
# test/support/factory.ex defmodule OurProject.Factory do use ExMachina.Ecto, repo: OurProject.Repo use OurProject.ClientFactory end
Once we have created our Factory module and our factories we can use them in any test importing the factory module. You can with ExMachina
you can build or insert test data, the main difference is that build returns an object that is not saved at the database. For more information read the Overview section of their repository
Here is an example test that inserts a client when we need it. Calling the client_fixture
function.
# test/our_project/client/some_client_test.ex defmodule OurProject.SomeClientTest do use OurProject.DataCase import OurProject.Factory def client_fixture(attrs \\ %{}) do # `insert*` returns an inserted comment. Only works with ExMachina.Ecto # Associated records defined on the factory are inserted as well. insert(:client, attrs) end ... end
Wallaby
We already have our data so we can start with the integration tests. Install wallaby following the instructions on their GitHub page and configure it with Chromedriver.
# config/test.exs config :wallaby, driver: Wallaby.Experimental.Chrome, chrome: [ headless: true ]
Now, we will create a FeatureCase module to configure the database, create the session and import the modules and helpers that our tests will need. Here we will import our Factory
module.
# test/support/feature_case.ex defmodule OurProject.FeatureCase do use ExUnit.CaseTemplate using do quote do use Wallaby.DSL import Wallaby.Query alias OurProject.Repo import Ecto import Ecto.Changeset import Ecto.Query #Import our Router Helpers import OurProject.Router.Helpers #Import custom helpers if we need them import OurProject.TestHelpers.Navigation #Import our ExMachina factories import OurProject.Factory end end # Connect to the test database and create the session for each test setup tags do :ok = Ecto.Adapters.SQL.Sandbox.checkout(OurProject.Repo) unless tags[:async] do Ecto.Adapters.SQL.Sandbox.mode(OurProject.Repo, {:shared, self()}) end metadata = Phoenix.Ecto.SQL.Sandbox.metadata_for(OurProject.Repo, self()) {:ok, session} = Wallaby.start_session(metadata: metadata) {:ok, session: session} end end
Finally, we are ready to create our first test. We are going to create a test that requires fake data so we can see how to use the factories inside an integration test.
#test/integration/client/delete_client.exs defmodule OurProject.DeleteClientTest do use OurProject.FeatureCase, async: false setup %{session: session} do client = insert(:client) {:ok, session: session, client: client} end test "remove client", %{session: session, client: client} do session |> visit("/clients", client.name) |> click(link(client.name)) |> click(link("delete")) |> assert_has(css(".toast-message", count: 1, text: "Client successfully deleted")) end end
GitHub Actions
We have our integration tests and we want to check them when we submit a pull request. With a few steps, we can configure our GitHub workflow to run the tests every time we push to the branch.
Chromedriver
We have to add Chromedriver to our CI. To do it we will use an action created by @nanasses
. Here you can read the documentation.
# .github/workflows/ci.yml - uses: nanasess/setup-chromedriver@master
Compile our project
We have to get the dependencies, compile the project and run the migrations.
# .github/workflows/ci.yml - name: Install Dependencies run: mix deps.get - run: mix compile - run: mix ecto.migrate
Compile our assets
In order to have our javascript compiled it's needed to compile our assets.
# .github/workflows/ci.yml - run: npm install working-directory: ./assets - run: npm run deploy --prefix ./assets
Run the tests
And finally, run the tests.
# .github/workflows/ci.yml - run: mix test --trace
Overview
There is our entire ci.yml
file.
name: Continuous Integration on: [push] # This workflow will build and test a Phoenix application that uses # PostgreSQL as a database. Will also cache dependencies and build # artifacts to speed up the build. jobs: test: env: MIX_ENV: ci DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres runs-on: ubuntu-latest services: db: env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: postgres image: postgres:11 ports: ['5432:5432'] options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v1.0.0 - name: Recover dependency cache uses: actions/cache@v1 id: deps_cache with: path: deps key: ${{ runner.OS }}-deps-${{ hashFiles('**/mix.lock') }} restore-keys: | ${{ runner.OS }}-deps-${{ env.cache-name }}- ${{ runner.OS }}-deps- ${{ runner.OS }}- - name: Recover build cache uses: actions/cache@v1 with: path: _build key: ${{ runner.OS }}-build-${{ env.cache-name }} restore-keys: | ${{ runner.OS }}-build- ${{ runner.OS }}- - uses: actions/setup-elixir@v1.0.0 with: otp-version: 22.x elixir-version: 1.9.x - uses: nanasess/setup-chromedriver@master - name: Install Dependencies run: mix deps.get - run: mix compile - run: mix ecto.migrate - run: npm install working-directory: ./assets - run: npm run deploy --prefix ./assets - run: mix test --trace
That's it
We have our tests created and running on GitHub. If you are interested in GitHub Actions, at Codegram we have a repository with GitHub Actions workflows that can be useful to you.
I hope you found this post useful. If you have any comments, questions or suggestions, tell us on Twitter!
Photo by Glenn Carstens-Peters on Unsplash
Top comments (0)