horizon-test: Support for Parallel execution & report fix.

main
abdullah.masood 2025-12-08 22:25:12 +05:00
parent 823c84c95d
commit 823c8cfcd5
5 changed files with 68 additions and 21 deletions

View File

@ -13,27 +13,31 @@ import com.utopiadeals.framework.BrowserContextManager;
import org.junit.jupiter.api.extension.*;
import java.io.File;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
public class ExtentReportExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, TestWatcher, TestExecutionExceptionHandler {
public class ExtentReportExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, TestWatcher, TestExecutionExceptionHandler {
private static ExtentReports extent;
private static final Map<String, ExtentTest> suite = new ConcurrentHashMap<>();
private static final ThreadLocal<ExtentTest> test = new ThreadLocal<>();
@Override
public void beforeAll(ExtensionContext context) throws Exception {
public void beforeAll(ExtensionContext context) {
if (extent == null) {
createExtentReports();
}
suite.computeIfAbsent(getClassName(context), k -> extent.createTest(getClassName(context)));
}
@Override
public void afterAll(ExtensionContext context) throws Exception {
public void afterAll(ExtensionContext context) {
if (extent != null) {
extent.flush();
}
@ -48,13 +52,23 @@ public class ExtentReportExtension implements BeforeAllCallback, AfterAllCallbac
}
@Override
public void beforeEach(ExtensionContext context) throws Exception {
String className = context.getTestClass().map(Class::getSimpleName).orElse("Unknown");
String testName = context.getTestMethod().map(m -> m.getName()).orElse("Unknown Test");
public void beforeEach(ExtensionContext context) {
String className = getClassName(context);
String methodName = getMethodName(context);
ExtentTest extentTest = extent.createTest(testName)
.assignCategory(className);
test.set(extentTest);
ExtentTest testSuite = suite.get(className);
if (testSuite != null) {
ExtentTest extentTestNode = testSuite.createNode(methodName);
test.set(extentTestNode);
}
}
@Override
public void afterEach(ExtensionContext context) {
// Do not clear the ThreadLocal here because JUnit invokes TestWatcher callbacks
// (testSuccessful/testFailed/testAborted) after AfterEach, which would make test.get() null
// inside those callbacks and cause NPEs. The ThreadLocal will be overwritten in beforeEach
// for the next test method and cleared at JVM end.
}
private void createExtentReports() {
@ -152,5 +166,17 @@ public class ExtentReportExtension implements BeforeAllCallback, AfterAllCallbac
}
}
private String getClassName(ExtensionContext context) {
return context.getTestClass()
.map(Class::getSimpleName)
.orElse("UnknownClass");
}
private String getMethodName(ExtensionContext context) {
return context.getTestMethod()
.map(Method::getName)
.orElse("UnknownMethod");
}
}

View File

@ -1,17 +1,23 @@
package apitestsuites;
import com.utopiadeals.api.RestWebCall;
import com.utopiadeals.framework.extensions.ExtentReportExtension;
import com.utopiadeals.utils.config.Constants;
import io.restassured.response.Response;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@ExtendWith(ExtentReportExtension.class)
@Tag("access-mgmt-api")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AccessManagementApiTest {
private static final String BASE_URL = Constants.getApiBaseUrl();
private static final String USERS_ENDPOINT = "/api/access-management/users";
@ -20,6 +26,7 @@ public class AccessManagementApiTest {
private static Integer userId;
@Test
@Order(1)
public void addUser_WithValidData_ShouldReturnSuccess() {
// Arrange
apiClient = new RestWebCall(BASE_URL, Constants.getApiTestUserName(), Constants.getApiTestPassword());
@ -50,6 +57,7 @@ public class AccessManagementApiTest {
}
@Test
@Order(2)
public void getUsers_WithValidEmailId_ShouldReturnSuccess() {
// Act
apiClient = new RestWebCall(BASE_URL, Constants.getApiTestUserName(), Constants.getApiTestPassword());
@ -62,6 +70,7 @@ public class AccessManagementApiTest {
}
@Test
@Order(3)
public void getUsers_WithValidId_ShouldReturnSuccess() {
// Act
apiClient = new RestWebCall(BASE_URL, Constants.getApiTestUserName(), Constants.getApiTestPassword());

View File

@ -4,13 +4,13 @@ import com.utopiadeals.framework.annotations.JsonTestDataExtension;
import com.utopiadeals.utils.TestDataProvider;
import com.utopiadeals.web.pages.LoginPage;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.params.ParameterizedTest;
public class LoginTest extends WebTestSuiteBase {
@DisplayName("Login Test")
@Tag("LoginTest")
@ParameterizedTest()
@JsonTestDataExtension("dataSet-0,dataSet-1")
public void loginTest(TestDataProvider testDataProvider) {

View File

@ -0,0 +1,12 @@
junit.jupiter.execution.parallel.enabled = true
# Run test METHODS sequentially within each class to preserve intended order
junit.jupiter.execution.parallel.mode.default = same_thread
# Allow different test classes to run in parallel
junit.jupiter.execution.parallel.mode.classes.default = concurrent
# Fixed parallelism for class-level concurrency
junit.jupiter.execution.parallel.config.strategy = fixed
junit.jupiter.execution.parallel.config.fixed.parallelism = 4
# Execute test methods in the order specified by @Order annotations
junit.jupiter.testmethod.order.default = org.junit.jupiter.api.MethodOrderer$OrderAnnotation

View File

@ -4,7 +4,7 @@
"dataSets": {
"dataSet-0": {
"username": "utest@utopiadeals.com",
"password": "utest0001"
"password": "utest001"
},
"dataSet-1": {
"username": "abdullah@utopiadeals.com",