Fl4m3Ph03n1x

Fl4m3Ph03n1x

How to have excoveralls consider total testing coverage from all apps in umbrella project?

Background

I am using excoveralls in an umbrella project with several children.

I have set up the children to use Excoveralls like this:

For normal Elixir applications:

 def project do
    [
      app: :app1,
      version: "3.1.0",
      build_path: "../../_build",
      config_path: "../../config/config.exs",
      deps_path: "../../deps",
      lockfile: "../../mix.lock",
      elixir: "~> 1.16",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      test_coverage: [tool: ExCoveralls],
      preferred_cli_env: preferred_cli_env()
    ]
  end

And for a Phoenix child, the configuration is slightly different:

def project do
    [
      app: :phoenix_app_1,
      version: "2.2.1",
      build_path: "../../_build",
      config_path: "../../config/config.exs",
      deps_path: "../../deps",
      lockfile: "../../mix.lock",
      elixir: "~> 1.16",
      elixirc_paths: elixirc_paths(Mix.env()),
      compilers: Mix.compilers(),
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      test_coverage: [tool: ExCoveralls],
      preferred_cli_env: preferred_cli_env()
    ]
  end

 defp deps do
    [
      # Phoenix
      # ....

      # I dont know why I have to explicity include excoveralls here
      # but if I dont `mix coveralls` wont work for Phoenix child apps
      {:excoveralls, "~> 0.18", only: :test},
    ]
  end

For both types of apps the preferred_cli_env set to this:

defp preferred_cli_env,
    do: [
      coveralls: :test,
      "coveralls.detail": :test,
      "coveralls.post": :test,
      "coveralls.html": :test,
      "coveralls.github": :test
    ]

Problem

When I run mix coveralls it runs all tests from each child app sequentially, due to my customized mix test alias:

defp aliases do
    child_tests =
      Path.wildcard("apps/*")
      |> Enum.map(&String.replace(&1, "apps/", ""))
      |> Enum.map(fn app -> "cmd --app #{app} mix test --color" end)

    [test: child_tests]
  end

So what ends up happening, is that coveralls will run the coverage for each app, and then only present me with the coverage for the last app run.

This is a problem. I don’t want the coverage of only the last child app, I want the coverage of all child apps, inside the project, so i know the overall test coverage of the project.

Questions

  • Is this possible to do with coveralls?
  • If so, how?

Marked As Solved

LostKobrakai

LostKobrakai

Named processes are a common pattern for sure. The issue is also not the named process by itself. The issue is the hardcoded dependencies on those names (and their backing process) into your codebase, which means tests can no longer opt out of using that named process in favor of another instance.

As soon as you look into applications we would generally consider to be libraries you see the pattern of keying a whole tree of processes to a given name all the time. E.g. in ecto processes are keyed to the repo name, in broadway the processes are keyed to the name of the broadway pipeline. E.g. see here how the MyBroadway name determines the names of all child processes: Broadway — Broadway v1.0.7

Also Liked

LostKobrakai

LostKobrakai

Tbh that sounds like you’re manually starting applications, which you generally shouldn’t need to be doing in the first place. If you have your dependencies setup correctly between your umbrella applications (using {:app, in_umbrella: true}) all necessary applications should start up no matter what mix task you run and if it’s for the whole umbrella or just a single app within.

LostKobrakai

LostKobrakai

Fair. You got global state in your application and your tests show you that this is not necessarily the best design.

My general suggestion for global state is refactoring those singleton processes (with a fixed name) to processes, which can be given a name. That way you can start multiple concurrent instances of those processes with different names.

Given that you can start a separate set of processes per test. You can use dependency injection (of various forms) to inject the name (or names) to be used by your business logic when interacting with those processes.

Production can use a single name (or names), which effectively gives you singleton behaviour in production.

The issues you run into are why I generally suggest that test should either not depend on state present on processes started by applications or at least that state should be keyed to the running test. That approach is essentially how the ecto sandbox or mox allow you to run tests concurrently.

While this is talking about processes the same can equally be applied to other global resources.

LostKobrakai

LostKobrakai

Usually, but I tend to mirror the order of parameters GenServer.call has as well. It’s imo the more reasonable order if you happen to pass both the server and item.

Last Post!

LostKobrakai

LostKobrakai

Usually, but I tend to mirror the order of parameters GenServer.call has as well. It’s imo the more reasonable order if you happen to pass both the server and item.

Where Next?

Popular in Questions Top

New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31494 112
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40042 209
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement