按时间段测试重复调用

testng repeat invocations by time period

我的经理要求我运行在预定义的时间段内进行某种性能和稳定性测试。

这意味着,重复 运行 进行同一组测试,测量各种事件,直到某个预定义的时间段过去。这是他的要求。

目前,我通过在涉及的各种方法上指定 invocationCount 来解决这个问题。然而,它变得越来越难以管理,因为添加了新方法,其中一部分 运行 并行或使用并行数据提供者,而另一部分则依赖于其他方法。此外,被测系统具有异步行为,有时响应速度更快,有时响应速度更慢。因此,总执行时间,尤其是长时间 运行ning 执行变得越来越难以预测,甚至难以计算。

我正在寻找类似 invocationCount 但具有时代气息的东西。指定后,只要还有剩余时间,它就应该像 invocationCount 一样重复调用。有人做过这样的事吗?

在高级别上,您需要执行以下操作才能实现此目标:

  1. 创建一个自定义注释,可用于说明 运行 的迭代次数和持续时间。
  2. 现在,对于所有需要此功能的测试方法,使用 (1) 中定义的自定义注释对其进行注释。
  3. 定义一个实现 TestNG 接口 org.testng.IHookable 的基础 class。
  4. run() 方法中,解析注释,然后使用执行器服务来控制持续时间和迭代。

自定义注解

import static java.lang.annotation.ElementType.METHOD;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({METHOD})
public @interface Repeatable {

  int forSeconds() default 0;

  int iterations() default 1;
}

基础class(仅当您有多个此类测试class具有相同需求时才需要)

import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.testng.IHookCallBack;
import org.testng.IHookable;
import org.testng.ITestResult;

public class AbstractTestCase implements IHookable {

  @Override
  public void run(IHookCallBack callBack, ITestResult testResult) {
    Repeatable repeatable =
        testResult.getMethod().getConstructorOrMethod().getMethod().getAnnotation(Repeatable.class);
    if (repeatable == null) {
      callBack.runTestMethod(testResult);
      return;
    }
    Callable<Void> task =
        () -> {
          for (int i = 1; i <= repeatable.iterations(); i++) {
            System.err.println("Running iteration : " + i);
            callBack.runTestMethod(testResult);
          }
          return null;
        };
    ExecutorService service = Executors.newFixedThreadPool(1);
    try {
      List<Future<Void>> result =
          service.invokeAll(
              Collections.singletonList(task), repeatable.forSeconds(), TimeUnit.SECONDS);
      service.shutdown();
      result.forEach(
          r -> {
            try {
              r.get();
            } catch (InterruptedException | ExecutionException e) {
              throw new RuntimeException(e);
            }
          });
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }
}

测试class

import java.util.concurrent.TimeUnit;
import org.testng.annotations.Test;

public class TestClassSample extends AbstractTestCase {

  @Test
  @Repeatable(forSeconds = 5, iterations = 10)
  public void runTask() throws InterruptedException {
    TimeUnit.SECONDS.sleep(1);
    System.err.println("Woke up after sleeping for 1 second");
  }
}

执行输出

Running iteration : 1
Woke up after sleeping for 1 second
Running iteration : 2
Woke up after sleeping for 1 second
Running iteration : 3
Woke up after sleeping for 1 second
Running iteration : 4
Woke up after sleeping for 1 second
Running iteration : 5
Running iteration : 6



java.util.concurrent.CancellationException
    at java.util.concurrent.FutureTask.report(FutureTask.java:121)
    at java.util.concurrent.FutureTask.get(FutureTask.java:192)
    at com.rationaleemotions.AbstractTestCase.lambda$run(AbstractTestCase.java:42)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at com.rationaleemotions.AbstractTestCase.run(AbstractTestCase.java:39)
    at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:255)
    at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:594)
    at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:174)
    at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
    at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:821)
    at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:147)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:588)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
    at org.testng.SuiteRunner.run(SuiteRunner.java:286)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1214)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1136)
    at org.testng.TestNG.runSuites(TestNG.java:1066)
    at org.testng.TestNG.run(TestNG.java:1034)
    at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
    at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:110)


===============================================
Default Suite
Total tests run: 1, Passes: 0, Failures: 1, Skips: 0
===============================================


Process finished with exit code 0