karolsluszniak/ex_check

How to re-run failed tests

Closed this issue · 3 comments

Hello!

I've been really enjoying this tool and using everywhere I can, and have one question:

I am working on a codebase with intermittently failing tests, causing me to have to frequently re-run the whole suite. I'm leading a push to fix the intermittent cases, but it is not going to be quick.

In the meantime I am hoping to speed up my local development by being able to retry mix test with just failed cases in the case of failure. Something like:

    {:ex_unit, umbrella: [parallel: false], env: %{"MIX_ENV" => "test"}, command: "mix test || mix test --failed"},

(I am running this on an umbrella app, and a lot of the issues are the result of a large global cache causing tests to share state)

But I have not been able to find a way to pass anything beyond a single command into :command.

I understand that what I am asking for is an anti-pattern and you may not wish the add the option of doing this, if that is the case would you be able to point me to where I could make the change in a fork of my own?

Thank you 🙂

Hello Alan! Great to hear ex_check is useful to you!

Well, anti-pattern or not, it's an interesting problem to tackle and one that's not so uncommon :)

Fortunately, it's possible with existing feature set of ex_check. Elixir's ports can't run such shell command directly, but you may create a proper shell script, say test/test_and_retry.sh, with content like the following:

#!/bin/sh
mix test || mix test --failed

Be sure to make it executable with chmod +x test/test_and_retry.sh and then override the default ex_unit tool configuration in .check.exs (run mix check.gen.config if you don't have one yet):

[
  tools: [
    {:ex_unit, "test/test_and_retry.sh"}
  ]
]

That's it. I've just tested it with a sample project with randomly failing test case and it works like a charm.


Btw ex_check also allows to run a tool as a dependency of other failing tool with config like below:

[
  tools: [
    {:ex_unit_retry, "mix test --failed", deps: [{:ex_unit, status: :error, else: :disable}]}
  ]
]

It works as expected except it doesn't mute the error from the original failing ex_unit call so the exit status from ex_check will also be non-zero. This would be an useful solution if you'd like to alarm yourself and the CI upon such failure but see if the retry helped the suite to pass - something that you could go for if you'd declare an open war to your failing tests and would like to hunt them down without mercy. You could even declare a chain of such retries to if a single retry is not enough. Otherwise, if you want the successful retry to make things green, then you're better off with the script.

Hope that helps.

Oh, there's also a way to do this without an extra script file, with mix cmd. Plus, added the --color flag to enforce colors in mix test called indirectly (as direct calls have colors enabled autmatically by ex_check hacking the mix command).

[
  tools: [
    {:ex_unit, ["mix", "cmd", "mix test --color || mix test --color --failed"]}
  ]
]

YES! This is perfect. This massively cut down my run times AND justified my recent ram upgrade! Thanks @karolsluszniak !

2020-09-28_11-57