29

eclipse->junit-view 中显示的测试执行时间取决于整个测试用例的执行,包括:

  • 测试数据准备
  • 执行业务逻辑
  • 断言结果

我需要一个关于我的业务逻辑的执行时间的更详细的陈述,并且只有我的业务逻辑。这就是我在测试用例中所做的:

Date lNow = new Date();
List<Geo> lAllBasisGeo = mGeoEvaluator.evaluateAllGeo(lGeoFixture.getGeo(), lAllGeo);
Date lStop = new Date();
System.out.println("Time of execution in seconds:"+((lStop.getTime()-lNow.getTime())/1000));

嗯...我想我以一种非常尴尬的方式确定时间。此外,我认为没有必要声明两个 Date 变量。

我需要建议更有效地编写该代码......

4

4 回答 4

35

在单元测试中,我希望使用 JUnit 4 注释向测试添加超时,以确定测试是否通过(足够快):

@Test(timeout=100)//let the test fail after 100 MilliSeconds
public void infinity() {
  while(true);
}

为了确定您的业务逻辑的确切运行时间,我会像您一样在您的关键代码路径之前和之后添加时间语句,重复几次以获得学术上正确的结果,然后再次删除语句,从而使代码精简。

long start = System.currentTimeMillis();
//execute logic in between
long end = System.currentTimeMillis();
System.out.println("DEBUG: Logic A took " + (end - start) + " MilliSeconds");
于 2013-02-15T11:54:40.853 回答
31

JUnit 4.12 引入了Stopwatch @Rule. 它使用起来非常简单,应该成为在测试期间验证所用时间的事实上的方法。这是一个展示其功能的示例类:

public static class StopwatchTest {
     private static final Logger logger = Logger.getLogger("");

     private static void logInfo(Description description, String status, long nanos) {
         String testName = description.getMethodName();
         logger.info(String.format("Test %s %s, spent %d microseconds",
                                   testName, status, TimeUnit.NANOSECONDS.toMicros(nanos)));
     }

     @Rule
     public Stopwatch stopwatch = new Stopwatch() {
         @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);
         }
     };

     @Test
     public void succeeds() {
     }

     @Test
     public void fails() {
         fail();
     }

     @Test
     public void skips() {
         assumeTrue(false);
     }

     @Test
     public void performanceTest() throws InterruptedException {
         // An example to assert runtime:
         long delta = 30;
         Thread.sleep(300L);
         assertEquals(300d, stopwatch.runtime(MILLISECONDS), delta);
         Thread.sleep(500L);
         assertEquals(800d, stopwatch.runtime(MILLISECONDS), delta);
     }
}
于 2015-01-09T20:45:32.060 回答
12

Guava 库中有一个非常有用的实用程序 -秒表
这将允许您编写以下内容

import com.google.common.base.Stopwatch;

final Stopwatch stopwatch = Stopwatch.createStarted();
//dostuff
System.out.println("Time of execution in seconds:" + stopwatch.stop().elapsed(TimeUnit.SECONDS));
于 2013-02-15T10:30:19.517 回答
0

如果您想对特定命令进行断言并忽略测试设置的延迟,您可以将 Stopwatch 仅用于您要检查的代码段。因此,如果您希望几个命令占用少于 500 毫秒:

Stopwatch stopwatch = createStarted();
firstCommandToBeTimed();
secondCommandToBeTimed();
assertThat(stopwatch.elapsed(TimeUnit.MILLISECONDS)).isLessThan(500);

现在Stopwatch 是测试版(在某些番石榴版本中),你会得到一些丑陋的 intellij 警告。此外,您可能不想使用 3rd 方库。在这种情况下,您可以使用 Instant 执行相同操作:

Instant start = Clock.systemDefaultZone().instant();
firstCommandToBeTimed();
secondCommandToBeTimed();
assertThat(start.until(Clock.systemDefaultZone().instant(), MILLIS)).isLessThan(500);

最后一点,如果您仍然想使用 Stopwatch,但想摆脱警告删除重复代码,您可以创建一个方法来包装您想要计时的代码并注释掉警告:

{
    assertExecutionTime(() -> {
        firstCommandToBeTimed();
        secondCommandToBeTimed();
    },  500);
}
//....
@SuppressWarnings("UnstableApiUsage")
private void assertExecutionTime(Runnable runnable, int timeoutInMillis) {
    Stopwatch stopwatch = createStarted();
    runnable.run();
    assertThat(stopwatch.elapsed(TimeUnit.MILLISECONDS)).isLessThan(timeoutInMillis);
}

(对于 Instant 可以采取类似的方法,以消除重复)

于 2021-10-08T22:44:46.937 回答