1

Is there a class/method I could implement within JUnit that is basically a "hook" that runs after each test case finishes, with user-defined (in code) metadata available?

I'm trying to accomplish something like this:

  • Annotate a test case with a user-defined annotation, such as team ownership (e.g. @Team(Teams.PAYMENTS))
  • Print test result to console with 3 values: test name (test function name), status (pass/fail), and team (annotation value)

For simplicity, I just need to print this info (later it will get published elsewhere), but I'm really lost in where I could obtain this test metadata information in one place, after the test runs?

I tried to override the finish method in one of our TestRunner class:

    override fun finish(resultCode: Int, results: Bundle?) {
        System.out.println("===breakpoint here===")

        super.finish(resultCode, results)
    }

but when debugging, there was no test metadata here. Any suggestions on how I could approach this?

Thank you!

Dragan R.
  • 598
  • 4
  • 18

1 Answers1

2

For JUnit 4, you can use a TestWatcher rule:

import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

public class TestWatcherAPIUnitTest {

    @Rule(order = Integer.MIN_VALUE)
    public TestWatcher watchman = new TestWatcher() {
        @Override
        protected void failed(Throwable e, Description description) {
            System.out.println(description + " Team: " + getTeam(description) + " failed!");
        }

        @Override
        protected void succeeded(Description description) {
            System.out.println(description + " Team: " + getTeam(description) + " success!");
        }

        String getTeam(Description description) {
            Team team = description.getAnnotation(Team.class);
            return (team != null) ? team.value() : "unknown_team";
        }


    };

    @Test
    @Team("team1")
    public void failing_test() {
        Assert.assertTrue(false);
    }

    @Test
    @Team("team2")
    public void successful_test() {
        Assert.assertTrue(true);
    }
}

Similarly, for JUnit5 there is a TestWatcher API

Lesiak
  • 22,088
  • 2
  • 41
  • 65
  • This is really nice, thank you @Lesiak! It seems like the scope of this Rule is this particular class only - is there a way to apply a rule across any test case that goes through a particular Test Runner? – Dragan R. Apr 21 '21 at 13:06
  • Apparently it can be done, with subclassing the runner to include the rule (I haven't tried it, though) Note that the rule above can be defined in a separate class, which is more palatable than defining it in place every time. See https://stackoverflow.com/questions/7639353/how-to-define-a-junit-method-rule-in-a-test-suite/7653558 – Lesiak Apr 21 '21 at 13:39
  • I'll try to combine both answers and give this approach a try. Thank you @Lesiak for your help! – Dragan R. Apr 21 '21 at 14:36