Balu
Balu

Reputation: 161

Why RunListener class testRunStarted() method calling multiple times for a single test in JUnit?

I have tried the example of JUnit listener given in the example in link

MyRunner.class

public class MyRunner extends BlockJUnit4ClassRunner {

public MyRunner(Class<?> klass) throws InitializationError {
    super(klass);
}

@Override public void run(RunNotifier notifier){
    notifier.addListener(new JUnitExecutionListener());
    notifier.fireTestRunStarted(getDescription());
    super.run(notifier);
}
}

JUnitExecutionListener.class

public class JUnitExecutionListener extends RunListener {

@Override
public void testRunStarted(Description description) throws Exception {
    System.out.println("Number of tests to execute: " + description.testCount());
}

@Override
public void testRunFinished(Result result) throws Exception {
    System.out.println("Number of tests executed: " + result.getRunCount());
}

@Override
public void testStarted(Description description) throws Exception {
    System.out.println("Starting: " + description.getMethodName());
}

@Override
public void testFinished(Description description) throws Exception {
    System.out.println("Finished: " + description.getMethodName());
}

@Override
public void testFailure(Failure failure) throws Exception {
    System.out.println("Failed: " + failure.getDescription().getMethodName());
}

@Override
public void testAssumptionFailure(Failure failure) {
    System.out.println("Failed: " + failure.getDescription().getMethodName());
}

@Override
public void testIgnored(Description description) throws Exception {
    System.out.println("Ignored: " + description.getMethodName());
}
}

I have 3 tests as below

Sample1Test.class

@RunWith(MyRunner.class)
public class Sample1Test {

@Test
public void step1() {
    System.out.println("Sample1Test step1");
}
}

Sample2Test.class

@RunWith(MyRunner.class)
public class Sample2Test {

@Test
public void step1() {
    System.out.println("Sample2Test step1");
}
}

Sample3Test.class

@RunWith(MyRunner.class)
public class Sample3Test {

@Test
public void step1() {
    System.out.println("Sample3Test step1");
}
}

On console I am getting log below,

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.demo.test.Sample1Test
Number of tests to execute: 1
Starting: step1
Sample1Test step1
Finished: step1
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.064 sec
Running com.demo.test.Sample2Test
Number of tests to execute: 1
Number of tests to execute: 1
Starting: step1
Starting: step1
Sample2Test step1
Finished: step1
Finished: step1
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec
Running com.demo.test.Sample3Test
Number of tests to execute: 1
Number of tests to execute: 1
Number of tests to execute: 1
Starting: step1
Starting: step1
Starting: step1
Sample3Test step1
Finished: step1
Finished: step1
Finished: step1
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec
Number of tests executed: 3
Number of tests executed: 3
Number of tests executed: 3

Why JUnitExecutionListener methods are getting called twice for second test and thrice for the third abd so on ? Can we have a fix for this so that each method should call only once ?

Note : I am using junit-4.12

Upvotes: 3

Views: 1280

Answers (2)

Pramod Karande
Pramod Karande

Reputation: 1

I had the same issue and I fixed it using a maven-surefire-plugin

you can register your custom JUnit listener by adding the below snippet in the maven-surefire plugin in pom.xml. No need to use a custom runner class and @RunWith annotation

<properties>
      <property>
          <name>listener</name>
          <value>path.to.listener.class</value>
      </property>
</properties>

Upvotes: 0

dvelopp
dvelopp

Reputation: 4305

RunNotifier is shared among all the children: org.junit.runners.ParentRunner#runChildren. It basically means that every time method "run" is invoked for one of your runners, the listener is added to the already existing RunNotifier object that may contain your listener already.

There are two ways I see to address the issue:

  1. Make your listener singleton object or just store it in a static field and then before adding just check whether or not it is already in the list.
  2. Remove your listener after the invocation of method run. Like this:

    super.run(notifier);
    notifier.removeListener(listener);
    

Hope it was helpful.

Upvotes: 1

Related Questions