Skip to content

Commit 66cbed7

Browse files
authored
feat: extensions for unit tests (#231)
Refs: #220
1 parent cc3d49a commit 66cbed7

8 files changed

+347
-205
lines changed

app/src/test/java/ch/sbb/polarion/extension/generic/fields/CustomFieldEnumConverterTest.java

+7-24
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,19 @@
22

33
import ch.sbb.polarion.extension.generic.fields.converters.ChainConverter;
44
import ch.sbb.polarion.extension.generic.fields.model.FieldMetadata;
5+
import ch.sbb.polarion.extension.generic.polarion.CustomExtensionMock;
6+
import ch.sbb.polarion.extension.generic.polarion.PlatformContextMockExtension;
57
import com.polarion.alm.shared.util.Pair;
68
import com.polarion.alm.tracker.ITrackerService;
7-
import com.polarion.platform.core.IPlatform;
8-
import com.polarion.platform.core.PlatformContext;
99
import com.polarion.platform.persistence.IDataService;
1010
import com.polarion.platform.persistence.IEnumOption;
1111
import com.polarion.platform.persistence.IEnumeration;
1212
import com.polarion.platform.persistence.spi.EnumOption;
1313
import com.polarion.subterra.base.data.model.internal.EnumType;
1414
import com.polarion.subterra.base.data.model.internal.ListType;
15-
import org.junit.jupiter.api.AfterEach;
1615
import org.junit.jupiter.api.BeforeEach;
1716
import org.junit.jupiter.api.Test;
1817
import org.junit.jupiter.api.extension.ExtendWith;
19-
import org.mockito.Answers;
20-
import org.mockito.Mock;
21-
import org.mockito.MockedStatic;
2218
import org.mockito.junit.jupiter.MockitoExtension;
2319

2420
import java.util.ArrayList;
@@ -32,31 +28,23 @@
3228
import static org.mockito.Mockito.lenient;
3329
import static org.mockito.Mockito.mock;
3430

35-
@ExtendWith(MockitoExtension.class)
31+
@ExtendWith({MockitoExtension.class, PlatformContextMockExtension.class})
3632
public class CustomFieldEnumConverterTest {
3733

3834
public static final String YES_NO_ENUM_ID = "yes_no";
3935
public static final Pair<String, String> YES = Pair.of("yes", "Ja");
4036
public static final Pair<String, String> NO = Pair.of("no", "Nein");
4137

42-
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
43-
MockedStatic<PlatformContext> mockPlatformContext;
38+
@CustomExtensionMock
39+
private IDataService dataService;
40+
@CustomExtensionMock
41+
private ITrackerService trackerService;
4442

4543
private ArrayList<IEnumOption> allOptions;
4644

4745
@BeforeEach
4846
@SuppressWarnings("unchecked")
4947
void setup() {
50-
IPlatform platform = mock(IPlatform.class);
51-
mockPlatformContext.when(PlatformContext::getPlatform).thenReturn(platform);
52-
53-
IDataService dataService = mock(IDataService.class);
54-
lenient().when(platform.lookupService(IDataService.class)).thenReturn(dataService);
55-
56-
ITrackerService trackerService = mock(ITrackerService.class);
57-
lenient().when(platform.lookupService(ITrackerService.class)).thenReturn(trackerService);
58-
lenient().when(trackerService.getDataService()).thenReturn(dataService);
59-
6048
IEnumeration<IEnumOption> enumeration = mock(IEnumeration.class);
6149
lenient().when(dataService.getEnumerationForEnumId(any(), any())).thenReturn(enumeration);
6250

@@ -66,11 +54,6 @@ void setup() {
6654
lenient().when(enumeration.getAllOptions()).thenReturn(allOptions);
6755
}
6856

69-
@AfterEach
70-
void cleanup() {
71-
mockPlatformContext.close();
72-
}
73-
7457
@Test
7558
void testGetEnumOptionById() {
7659
FieldMetadata fieldMetadata = ConverterTestUtils.getWorkItemCustomField();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package ch.sbb.polarion.extension.generic.polarion;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.FIELD)
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface CustomExtensionMock {
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package ch.sbb.polarion.extension.generic.polarion;
2+
3+
import org.junit.jupiter.api.extension.ExtensionContext;
4+
5+
import java.lang.reflect.Field;
6+
7+
public class CustomExtensionMockInjector {
8+
9+
public static <T> void inject(ExtensionContext context, T what) throws IllegalAccessException {
10+
Object testInstance = context.getTestInstance().orElse(null);
11+
if (testInstance != null) {
12+
for (Field field : testInstance.getClass().getDeclaredFields()) {
13+
if (field.isAnnotationPresent(CustomExtensionMock.class) && field.getType().isAssignableFrom(what.getClass())) {
14+
field.setAccessible(true);
15+
field.set(testInstance, what);
16+
}
17+
}
18+
}
19+
}
20+
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package ch.sbb.polarion.extension.generic.polarion;
2+
3+
import com.polarion.alm.projects.IProjectService;
4+
import com.polarion.alm.tracker.ITestManagementService;
5+
import com.polarion.alm.tracker.ITrackerService;
6+
import com.polarion.platform.IPlatformService;
7+
import com.polarion.platform.core.IPlatform;
8+
import com.polarion.platform.core.PlatformContext;
9+
import com.polarion.platform.persistence.IDataService;
10+
import com.polarion.platform.security.ILoginPolicy;
11+
import com.polarion.platform.security.ISecurityService;
12+
import com.polarion.platform.service.repository.IRepositoryService;
13+
import com.polarion.portal.internal.server.navigation.TestManagementServiceAccessor;
14+
import org.junit.jupiter.api.extension.AfterEachCallback;
15+
import org.junit.jupiter.api.extension.BeforeEachCallback;
16+
import org.junit.jupiter.api.extension.ExtensionContext;
17+
import org.mockito.MockedConstruction;
18+
import org.mockito.MockedStatic;
19+
20+
import static org.mockito.Mockito.*;
21+
22+
public class PlatformContextMockExtension implements BeforeEachCallback, AfterEachCallback {
23+
24+
private MockedConstruction<TestManagementServiceAccessor> testManagementServiceAccessorMockedConstruction;
25+
private MockedStatic<PlatformContext> platformContextMockedStatic;
26+
27+
@Override
28+
public void beforeEach(ExtensionContext context) throws Exception {
29+
IPlatform platformMock = mock(IPlatform.class);
30+
31+
ITrackerService trackerService = mock(ITrackerService.class);
32+
IProjectService projectService = mock(IProjectService.class);
33+
ISecurityService securityService = mock(ISecurityService.class);
34+
IPlatformService platformService = mock(IPlatformService.class);
35+
IRepositoryService repositoryService = mock(IRepositoryService.class);
36+
IDataService dataService = mock(IDataService.class);
37+
ILoginPolicy loginPolicy = mock(ILoginPolicy.class);
38+
ITestManagementService testManagementService = mock(ITestManagementService.class);
39+
40+
lenient().when(platformMock.lookupService(ITrackerService.class)).thenReturn(trackerService);
41+
lenient().when(platformMock.lookupService(IProjectService.class)).thenReturn(projectService);
42+
lenient().when(platformMock.lookupService(ISecurityService.class)).thenReturn(securityService);
43+
lenient().when(platformMock.lookupService(IPlatformService.class)).thenReturn(platformService);
44+
lenient().when(platformMock.lookupService(IRepositoryService.class)).thenReturn(repositoryService);
45+
lenient().when(platformMock.lookupService(IDataService.class)).thenReturn(dataService);
46+
lenient().when(platformMock.lookupService(ILoginPolicy.class)).thenReturn(loginPolicy);
47+
48+
lenient().when(trackerService.getDataService()).thenReturn(dataService);
49+
50+
platformContextMockedStatic = mockStatic(PlatformContext.class);
51+
platformContextMockedStatic.when(PlatformContext::getPlatform).thenReturn(platformMock);
52+
53+
CustomExtensionMockInjector.inject(context, trackerService);
54+
CustomExtensionMockInjector.inject(context, projectService);
55+
CustomExtensionMockInjector.inject(context, securityService);
56+
CustomExtensionMockInjector.inject(context, platformService);
57+
CustomExtensionMockInjector.inject(context, repositoryService);
58+
CustomExtensionMockInjector.inject(context, dataService);
59+
CustomExtensionMockInjector.inject(context, loginPolicy);
60+
61+
testManagementServiceAccessorMockedConstruction = mockConstruction(TestManagementServiceAccessor.class, (testManagementServiceAccessor, mockedContructionContext) -> {
62+
lenient().when(testManagementServiceAccessor.getTestingService()).thenReturn(testManagementService);
63+
});
64+
}
65+
66+
@Override
67+
public void afterEach(ExtensionContext context) throws Exception {
68+
if (testManagementServiceAccessorMockedConstruction != null) {
69+
testManagementServiceAccessorMockedConstruction.close();
70+
}
71+
if (platformContextMockedStatic != null) {
72+
platformContextMockedStatic.close();
73+
}
74+
}
75+
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package ch.sbb.polarion.extension.generic.polarion;
2+
3+
import com.polarion.alm.shared.api.transaction.RunnableInReadOnlyTransaction;
4+
import com.polarion.alm.shared.api.transaction.TransactionalExecutor;
5+
import com.polarion.alm.shared.api.transaction.internal.InternalReadOnlyTransaction;
6+
import com.polarion.alm.shared.api.utils.RunnableWithResult;
7+
import com.polarion.alm.shared.api.utils.internal.InternalPolarionUtils;
8+
import org.junit.jupiter.api.extension.AfterEachCallback;
9+
import org.junit.jupiter.api.extension.BeforeEachCallback;
10+
import org.junit.jupiter.api.extension.ExtensionContext;
11+
import org.junit.jupiter.api.extension.ParameterContext;
12+
import org.junit.jupiter.api.extension.ParameterResolutionException;
13+
import org.junit.jupiter.api.extension.ParameterResolver;
14+
import org.mockito.MockedStatic;
15+
16+
import static org.mockito.ArgumentMatchers.any;
17+
import static org.mockito.Mockito.*;
18+
19+
public class TransactionalExecutorExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {
20+
21+
private MockedStatic<TransactionalExecutor> transactionalExecutorMockedStatic;
22+
23+
@Override
24+
public void beforeEach(ExtensionContext context) throws Exception {
25+
transactionalExecutorMockedStatic = mockStatic(TransactionalExecutor.class);
26+
27+
InternalReadOnlyTransaction internalReadOnlyTransactionMock = mock(InternalReadOnlyTransaction.class);
28+
transactionalExecutorMockedStatic.when(() -> TransactionalExecutor.executeSafelyInReadOnlyTransaction(any())).thenAnswer(invocation -> {
29+
RunnableInReadOnlyTransaction<?> runnable = invocation.getArgument(0);
30+
return runnable.run(internalReadOnlyTransactionMock);
31+
});
32+
transactionalExecutorMockedStatic.when(TransactionalExecutor::currentTransaction).thenReturn(internalReadOnlyTransactionMock);
33+
34+
InternalPolarionUtils internalPolarionUtils = mock(InternalPolarionUtils.class);
35+
lenient().when(internalPolarionUtils.executeInBaseline(any(), any())).thenAnswer(invocation -> {
36+
RunnableWithResult<?> runnableWithResult = invocation.getArgument(1);
37+
return runnableWithResult.run();
38+
});
39+
lenient().when(internalReadOnlyTransactionMock.utils()).thenReturn(internalPolarionUtils);
40+
41+
CustomExtensionMockInjector.inject(context, internalPolarionUtils);
42+
CustomExtensionMockInjector.inject(context, internalReadOnlyTransactionMock);
43+
}
44+
45+
@Override
46+
public void afterEach(ExtensionContext context) throws Exception {
47+
if (transactionalExecutorMockedStatic != null) {
48+
transactionalExecutorMockedStatic.close();
49+
}
50+
}
51+
52+
@Override
53+
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
54+
return parameterContext.getParameter().getType().equals(ExtensionContext.class);
55+
}
56+
57+
@Override
58+
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
59+
return extensionContext;
60+
}
61+
62+
}

app/src/test/java/ch/sbb/polarion/extension/generic/service/PolarionServiceTest.java

+28-14
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
import ch.sbb.polarion.extension.generic.fields.FieldType;
55
import ch.sbb.polarion.extension.generic.fields.model.FieldMetadata;
66
import ch.sbb.polarion.extension.generic.fields.model.Option;
7+
import ch.sbb.polarion.extension.generic.polarion.PlatformContextMockExtension;
8+
import ch.sbb.polarion.extension.generic.polarion.TransactionalExecutorExtension;
79
import ch.sbb.polarion.extension.generic.util.AssigneeUtils;
810
import ch.sbb.polarion.extension.generic.util.TestUtils;
911
import com.polarion.alm.projects.IProjectService;
1012
import com.polarion.alm.projects.model.IProject;
11-
import com.polarion.alm.shared.api.transaction.TransactionalExecutor;
13+
import com.polarion.alm.shared.api.model.baselinecollection.BaselineCollection;
14+
import com.polarion.alm.shared.api.model.baselinecollection.BaselineCollectionReference;
15+
import com.polarion.alm.shared.api.transaction.ReadOnlyTransaction;
1216
import com.polarion.alm.tracker.IModuleManager;
1317
import com.polarion.alm.tracker.ITrackerService;
1418
import com.polarion.alm.tracker.model.IModule;
@@ -34,6 +38,7 @@
3438
import org.junit.jupiter.api.Test;
3539
import org.junit.jupiter.api.extension.ExtendWith;
3640
import org.mockito.Mock;
41+
import org.mockito.MockedConstruction;
3742
import org.mockito.MockedStatic;
3843
import org.mockito.junit.jupiter.MockitoExtension;
3944

@@ -48,7 +53,7 @@
4853
import static org.mockito.ArgumentMatchers.anyString;
4954
import static org.mockito.Mockito.*;
5055

51-
@ExtendWith(MockitoExtension.class)
56+
@ExtendWith({MockitoExtension.class, PlatformContextMockExtension.class, TransactionalExecutorExtension.class})
5257
@SuppressWarnings({"rawtypes", "unchecked", "UnusedReturnValue"})
5358
public class PolarionServiceTest {
5459

@@ -120,11 +125,14 @@ void testGetNotExistentModule() {
120125

121126
@Test
122127
void testGetNotExistentCollection() {
123-
try (MockedStatic<TransactionalExecutor> transactionalExecutorMockedStatic = mockStatic(TransactionalExecutor.class)) {
124-
mockProject(Boolean.TRUE);
125-
IBaselineCollection collection = mockCollection(Boolean.FALSE);
126-
transactionalExecutorMockedStatic.when(() -> TransactionalExecutor.executeSafelyInReadOnlyTransaction(any())).thenReturn(collection);
128+
mockProject(Boolean.TRUE);
129+
IBaselineCollection collection = mockCollection(Boolean.FALSE);
127130

131+
try (MockedConstruction<BaselineCollectionReference> baselineCollectionReferenceMockedConstruction = mockConstruction(BaselineCollectionReference.class, (mock, context) -> {
132+
BaselineCollection baselineCollection = mock(BaselineCollection.class);
133+
when(baselineCollection.getOldApi()).thenReturn(collection);
134+
when(mock.get(any(ReadOnlyTransaction.class))).thenReturn(baselineCollection);
135+
})) {
128136
ObjectNotFoundException exception = assertThrows(ObjectNotFoundException.class, () -> polarionService.getCollection(PROJECT_ID, COLLECTION_ID));
129137
assertEquals("Collection with id '1' not found in project 'project_id'", exception.getMessage());
130138

@@ -217,22 +225,28 @@ void testGetModuleWithRevision() {
217225

218226
@Test
219227
void testGetCollection() {
220-
try (MockedStatic<TransactionalExecutor> transactionalExecutorMockedStatic = mockStatic(TransactionalExecutor.class)) {
221-
mockProject(Boolean.TRUE);
222-
IBaselineCollection collection = mockCollection(Boolean.TRUE);
223-
transactionalExecutorMockedStatic.when(() -> TransactionalExecutor.executeSafelyInReadOnlyTransaction(any())).thenReturn(collection);
228+
mockProject(Boolean.TRUE);
229+
IBaselineCollection collection = mockCollection(Boolean.TRUE);
224230

231+
try (MockedConstruction<BaselineCollectionReference> baselineCollectionReferenceMockedConstruction = mockConstruction(BaselineCollectionReference.class, (mock, context) -> {
232+
BaselineCollection baselineCollection = mock(BaselineCollection.class);
233+
when(baselineCollection.getOldApi()).thenReturn(collection);
234+
when(mock.get(any(ReadOnlyTransaction.class))).thenReturn(baselineCollection);
235+
})) {
225236
assertNotNull(polarionService.getCollection(PROJECT_ID, COLLECTION_ID));
226237
}
227238
}
228239

229240
@Test
230241
void testGetCollectionWithRevision() {
231-
try (MockedStatic<TransactionalExecutor> transactionalExecutorMockedStatic = mockStatic(TransactionalExecutor.class)) {
232-
mockProject(Boolean.TRUE);
233-
IBaselineCollection collection = mockCollection(Boolean.TRUE);
234-
transactionalExecutorMockedStatic.when(() -> TransactionalExecutor.executeSafelyInReadOnlyTransaction(any())).thenReturn(collection);
242+
mockProject(Boolean.TRUE);
243+
IBaselineCollection collection = mockCollection(Boolean.TRUE);
235244

245+
try (MockedConstruction<BaselineCollectionReference> baselineCollectionReferenceMockedConstruction = mockConstruction(BaselineCollectionReference.class, (mock, context) -> {
246+
BaselineCollection baselineCollection = mock(BaselineCollection.class);
247+
when(baselineCollection.getOldApi()).thenReturn(collection);
248+
when(mock.get(any(ReadOnlyTransaction.class))).thenReturn(baselineCollection);
249+
})) {
236250
assertNotNull(polarionService.getCollection(PROJECT_ID, COLLECTION_ID, REVISION));
237251

238252
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,

0 commit comments

Comments
 (0)