Currently, when you run mix test in an umbrella app, it recursively runs mix test in each child app, so that the tests for app b do not begin running until the tests for a have completed. For our project, we’re making extensive use of the umbrella feature and have a large number of child apps. We decided we’d like to be able to run all the tests for all child apps together. Running all tests together provides a few benefits:
async: true. A small app with only one or two test modules with async: true cannot fully utilize all cores when the tests are run for just that app, but when run together with all tests in the entire project it can.async: true on a test module that can’t actually be run async. When we got all tests to run together using a new test_all task (see below), we immediately had to deal with a number of new failures due to tests defined in async: true modules that could not actually run async. We had to fix the tests or change async: true to async: false. The problem never occurred when running each apps test suite individually, because the tests that could not run at the same time were from different apps. It’s nice to learn about these issues ASAP (ideally, as soon as the problematic test is defined) instead of later, but it’s easy when each app’s test suite runs individually to not realize the problem — particularly if a sub-app has only one test module (and therefore wasn’t running concurrently with anything!).test_util app in the umbrella that contains test utilities and helper functions used by many of the other apps. Many of these functions are not directly called in the test_util test suite and as a result they are not counted as covered when we use the excoveralls tasks (which run each child app’s suite independently, like mix test). However, they do get called from tests in some of the other child apps, and should be counted as covered. I believe they would be counted if we were able to run all tests together from the excoveralls tasks.More generally, running all tests together seems to be in line with the recent changes in 1.2 that allow child apps in an umbrella to share the same config and build directories.
Anyhow, while elixir doesn’t currently provide a simple way to achieve this, I was able to figure a way out. I got it to work using a combination of test_paths and a new task that delegates to Mix.Tasks.Test:
defmodule MyProject.Mixfile do
use Mix.Project
def project do
[
# ...
test_paths: test_paths,
preferred_cli_env: %{ test_all: :test },
# ...
]
end
defp test_paths do
"apps/*/test" |> Path.wildcard |> Enum.sort
end
end
# `mix test` cd's into each app directory in sequence and runs the tests.
# `mix test_all` runs tests for all apps at the same time.
defmodule Mix.Tasks.TestAll do
use Mix.Task
@shortdoc "Runs all delorean tests at once"
defdelegate run(args), to: Mix.Tasks.Test
end
Note that setting test_paths did not affect mix test at all — since Mix.Tasks.Test is tagged as being recursive, it still runs individually against each child app. So I had to define a new task to make this work.
We’ve been using mix test_all for about a month and it’s working well for us. However, I worked on setting up coveralls.io yesterday and I couldn’t get it to integrate with excoveralls. Our coveralls tasks are running each child app’s suite independently and reporting less accurate coverage results. Excoveralls allows you to configure a test_task and I tried doing that (via test_coverage: [test_task: "test_all"]) but it led to an error from mix that I'm not sure how to solve:
** (RuntimeError) Trying to access Mix.Project.app_path for an umbrella project but umbrellas have no app
(mix) lib/mix/project.ex:316: Mix.Project.app_path/1
(mix) lib/mix/project.ex:337: Mix.Project.compile_path/1
(mix) lib/mix/tasks/test.ex:163: Mix.Tasks.Test.run/1
lib/mix/tasks.ex:43: Mix.Tasks.Coveralls.do_run/2
(mix) lib/mix/cli.ex:58: Mix.CLI.run_task/2
(For more info an the excoveralls accuracy reporting issue and discussion of this error, see parroty/excoveralls#23).
So, my proposal is for elixir to provide a simpler way for umbrella projects to run all child app test suites together — ideally in a way that would “just work” with excoveralls and similar coverage tools.
Thoughts? I’m willing to work up a PR to work on this.
Thanks,
Myron
--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CADUxQmu2DVjB%2BOdhFF7GYYrFc3U7DMXx0JXKdpk6EFixwzcvAA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.