Record time it takes JUnit tests to run

2019-03-19 17:16发布

问题:

I would like to record how long it takes my JUnit test to run programmatically. I have a large number of tests in various test classes, and I would like to find out how long each individual test method takes to run.

I can change the inheritance structure or annotate methods differently, but I would like to avoid having to add code within the test method itself and also within the before/after methods which are used to setup test business logic.

回答1:

You could use the JUnit StopWatch rule and override its methods as provided in the JUnit API documentation and have the time printed to console or log file for each test just by including one line of code in each of your individual test case class.

  1. Create your Customer StopWatch class (Sample provided)

    import java.util.concurrent.TimeUnit;
    import org.junit.AssumptionViolatedException;
    import org.junit.rules.Stopwatch;
    import org.junit.runner.Description;
    
    public class MyJUnitStopWatch extends Stopwatch{
    
    private static void logInfo(Description description, String status, long nanos) {
        String testName = description.getMethodName();
        System.out.println(String.format("Test %s %s, spent %d microseconds",
                                  testName, status, TimeUnit.NANOSECONDS.toMicros(nanos)));
    }
    
     @Override
       protected void succeeded(long nanos, Description description) {
           logInfo(description, "succeeded", nanos);
       }
    
       @Override
       protected void failed(long nanos, Throwable e, Description description) {
           logInfo(description, "failed", nanos);
       }
    
       @Override
       protected void skipped(long nanos, AssumptionViolatedException e, Description description) {
           logInfo(description, "skipped", nanos);
       }
    
       @Override
       protected void finished(long nanos, Description description) {
           logInfo(description, "finished", nanos);
       }    
    }
    
  2. Have a ParentTestClass created with that line and each of your test class inherit the parent test class:

    public class ParentTestCase {
    
    
    @Rule
    public MyJUnitStopWatch stopwatch = new MyJUnitStopWatch();
    
    }
    

Child classes inherits parent. No other change in Child classes or before or after methods.

public class TestUniqueCharacterString extends ParentTestCase {    

    private String uniqueChars = null;

    @Before
    public void before(){
        uniqueChars = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnop";
    }

    @Test
    public void testMyUniqueCharacterMethod(){


        UniqueCharacteString.doesStringHaveUniqueCharacters(uniqueChars);
    }

Or

  1. Include this line in each of your Test class

    @Rule
    public MyJUnitStopWatch stopwatch = new MyJUnitStopWatch();
    

    Sample Test Class:

    import org.junit.After;
    import org.junit.Before;
    import org.junit.Rule;
    import org.junit.Test;
    
    
    
    public class TestUniqueCharacterString {    
    
    @Rule
    public MyJUnitStopWatch stopwatch = new MyJUnitStopWatch();
    
    private String uniqueChars = null;
    
    @Before
    public void before(){
        uniqueChars = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnop";
    }
    
    @Test
    public void testMyUniqueCharacterMethod(){
    
    
        UniqueCharacteString.doesStringHaveUniqueCharacters(uniqueChars);
    }
    
    @Test
    public void testGoodIsUniqueMethod(){
            UniqueCharacteString.isUniqueCharacs(uniqueChars);
    }
    
    @Test
    public void testGoodIsUniqueMethodWithoutArray(){
        UniqueCharacteString.isUniqueCharsWithoutArray(uniqueChars);
    }
    
    @After
    public void after(){
        uniqueChars = "";
    }    
     }
    

JUnit API reference:

http://junit.org/apidocs/org/junit/rules/Stopwatch.html

Sample Output

Test testMyUniqueCharacterMethod succeeded, spent 3250 microseconds
Test testMyUniqueCharacterMethod finished, spent 3250 microseconds
Test testGoodIsUniqueMethod succeeded, spent 70 microseconds
Test testGoodIsUniqueMethod finished, spent 70 microseconds
Test testGoodIsUniqueMethodWithoutArray succeeded, spent 54 microseconds
Test testGoodIsUniqueMethodWithoutArray finished, spent 54 microseconds

It will also show time for failed and skipped test cases.



回答2:

Try to use @Before and @After. A method annotated with @Before or @After runs before or after the test.

    @Before
    public void start() {
        start = System.currentTimeMillis();
    }

    @After
    public void end() {
        System.out.println(System.currentTimeMillis() - start);
    }


回答3:

You can also create a @Rule and instantiate the TestWatcher class. This is what worked for me. This is being defined in a class that extends TestCase.

public class CompositeWithTeardownDBUnitTest extends DBTestCase {

DBTestCase extends TestCase

code snippet in CompositeWithTeardownDBUnitTest

@Rule
public TestRule watcher = new TestWatcher() {

    protected void starting(Description description) {
        timeStart = System.currentTimeMillis();
        cal = Calendar.getInstance();
        System.out
                .println("===========================================================================");
        System.out.println("Test: " + description.getMethodName());
        System.out.println("Start Time: " + dateFormat.format(cal.getTime()));
        System.out
                .println("===========================================================================");
    }

    protected void finished(Description description) {
        timeEnd = System.currentTimeMillis();
        double seconds = (timeEnd-timeStart)/1000.0;
        System.out
        .println("\n===========================================================================");
        System.out
        .println("Test completed - ran in: "+new DecimalFormat("0.000").format(seconds)+" sec");
        System.out
        .println("===========================================================================\n");

    }
};

And the JUnit test classes just extend this class CompositeWithTeardownDBUnitTest.



回答4:

Create your own TestWatcher implementation which catches every test method running. Using Guava Stopwatch you can measure time for each test:

public class TimeTestWatcher extends TestWatcher {
    private Stopwatch stopwatch = Stopwatch.createUnstarted();

    protected void starting(Description description) {
        stopwatch.start();
    }

    protected void finished(Description description) {
        stopwatch.stop();

        String testName = description.getMethodName();
        long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
        System.out.println(String.format("Test %s took %d ms.", testName, elapsed));
    }
};

And then add JUnit @Rule annotation with your TimeTestWatcher for each test class:

public class YourTest {

    @Rule
    public TimeTestWatcher watcher = new TimeTestWatcher();

    @Test
    public void testXXX() {}

    @Test
    public void testYYY() {}
}


回答5:

In addition to existing answers, you can use a rule for test name along with Before and After methods to display method name on log. Like this:

public class ImageSavingTest {
    @Rule
    public TestName name = new TestName();

    private long start;

    @Before
    public void start() {
        start = System.currentTimeMillis();
    }

    @After
    public void end() {
        System.out.println("Test " + name.getMethodName() + " took " + (System.currentTimeMillis() - start) + " ms");
    }

    @Test
    public void foobar() {
        // test code here
    }
}

Will output:

Test foobar took 1828 ms



回答6:

You could create a JUnit Rule that would record the time between before/after calls. This rule could be used as an instance and/or class rule to get you the time for each individual test method as well as for each test class.



回答7:

If you use @Before and @After annotations and note the junit testcase start and endtime. Then finding the difference of two timestamps should give you the testcase execution time. Something like this:

 public class Example {

    long startTime;
    long endTime;

    @Before public void recordStartTime() {
        startTime = System.currentTimeMillis();
    }
    @Test public void testSomething() {
          //test method
    }
    @After public void recordEndAndExecutionTime() {
        endTime = System.currentTimeMillis();
        System.out.println("Last testcase exection time in millisecond : " + (endTime - startTime));
    }
 }