多线程 Kotlin 测试中出现 AllureLifecycle 错误

问题描述 投票:0回答:1

我在 UserManager 类中有一个 @Step 注释的 Kotlin 方法,它向 SQL 数据库添加一个条目:

@Step("Insert record")
fun insertAll(
    profileId: String,
) {
    userDAO.insertAll(
        profileId = profileId
    )
}

如果我在单线程模式下从 @Test 注解的方法调用它,那么一切都会正常工作。

for (i in 0..usersCount) {
    userManager.insertAll(
        profileId
    )
}

但是如果我使用parallelStream(),就会发生奇怪的事情。

(0..usersCount)
    .toList()
    .parallelStream()
    .forEach {
        userManager.insertAll(
            profileId
        )
    }

一方面,代码继续工作,我的工作效率得到提高,但另一方面,日志中充满了相同类型的错误消息:

15:36:27.762 ERROR [AllureLifecycle] : Could not start step: no test case running
15:36:27.764 ERROR [AllureLifecycle] : Could not update step: no step running
15:36:27.764 ERROR [AllureLifecycle] : Could not stop step: no step running

依赖关系:

implementation("io.qameta.allure:allure-java-commons:2.21.0")

我做错了什么?

multithreading kotlin java-stream allure
1个回答
0
投票

parallelStream
的问题是它使用共享线程池,该线程池可能有也可能没有当前执行的测试或步骤的上下文。

为了解决这个问题,有一个 API 方法

Allure.getLifecycle().setCurrentTestCase(String)
可用。因此,要解决这个问题,您需要从主线程获取当前测试用例 UUID 并将其设置在工作线程中(在使用任何其他 Allure API 之前):

val currentTestCase = Allure.getLifecycle().currentTestCase.orElseThrow()
(0..usersCount)
    .toList()
    .parallelStream()
    .forEach {
        Allure.getLifecycle().setCurrentTestCase(currentTestCase);
        userManager.insertAll(
            profileId
        )
    } 

但是,如果您需要围绕该代码创建一个包装步骤,它将被忽略(因为我们只将测试上下文设置到工作线程中)。不幸的是,目前还没有可用的方法来设置当前步骤上下文。因此,要解决此问题,您需要使用低级(生命周期)API 来创建步骤:

Allure.step("child steps run in parallel", ThrowableRunnableVoid {
    // get the current step context
    val parentUuid = Allure.getLifecycle()
        .currentTestCaseOrStep.orElseThrow()

    (0..usersCount)
        .toList()
        .parallelStream()
        .forEach {
            val uuid = UUID.randomUUID().toString()
            // parentUuid is essential. Instead of using value from ThreadLocal,
            // provide parent context directly
            Allure.getLifecycle().startStep(
                parentUuid, uuid, StepResult()
                    .setName("userManager.insertAll(${profileId})")
            )
            try {
                // run your code here
                userManager.insertAll(
                   profiled
                )

                // if no exception, update the step
                Allure.getLifecycle()
                    .updateStep(uuid) { step: StepResult ->
                        step.setStatus(
                            Status.PASSED
                        )
                    }
            } catch (e: Exception) {
                // process the exception
                Allure.getLifecycle()
                    .updateStep(uuid) { s: StepResult ->
                        s
                            .setStatus(
                                ResultsUtils.getStatus(e).orElse(Status.BROKEN)
                            )
                            .setStatusDetails(ResultsUtils.getStatusDetails(e).orElse(null))
                    }
                ExceptionUtils.sneakyThrow<RuntimeException>(e)
            } finally {
                // finally stop the step
                Allure.getLifecycle().stopStep(uuid)
            }
        }
© www.soinside.com 2019 - 2024. All rights reserved.