This is an automated email from the ASF dual-hosted git repository.

jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git


The following commit(s) were added to refs/heads/2.x by this push:
     new 6a417a7e4d test: add UT for rm.fence (#7731)
6a417a7e4d is described below

commit 6a417a7e4da958dca2f1606566dc0c5cd4b0b7ab
Author: maple <[email protected]>
AuthorDate: Mon Oct 27 11:22:05 2025 +0800

    test: add UT for rm.fence (#7731)
---
 changes/en-us/2.x.md                               |   1 +
 changes/zh-cn/2.x.md                               |   1 +
 .../rm/fence/FenceLogCleanRunnableUnitTest.java    | 165 ++++++++++++++++
 .../seata/rm/fence/FenceLogIdentityTest.java       | 192 +++++++++++++++++++
 .../seata/rm/fence/SpringFenceConfigTest.java      | 125 ++++++++++++
 .../seata/rm/fence/SpringFenceHandlerUnitTest.java | 209 +++++++++++++++++++++
 6 files changed, 693 insertions(+)

diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 5613384abf..c4929c3507 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -91,6 +91,7 @@ Add changes here for all PR submitted to the 2.x branch.
 - [[#7725](https://github.com/apache/incubator-seata/pull/7725)] add UT for 
compressor module
 - [[#7718](https://github.com/apache/incubator-seata/pull/7718)] add UT for 
config module
 - [[#7723](https://github.com/apache/incubator-seata/pull/7723)] add UT for 
fastjson2 to test PostgreSQL Array type
+- [[#7731](https://github.com/apache/incubator-seata/pull/7731)] add UT for 
rm.fence
 
 
 ### refactor:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index 5b71604880..85bb2600f4 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -90,6 +90,7 @@
 - [[#7725](https://github.com/apache/incubator-seata/pull/7725)] 
为compressor模块增加单测
 - [[#7718](https://github.com/apache/incubator-seata/pull/7718)] 为config模块增加单测
 - [[#7723](https://github.com/apache/incubator-seata/pull/7723)] 添加 fastjson2 
的 UT 来测试 PostgreSQL 数组类型
+- [[#7731](https://github.com/apache/incubator-seata/pull/7731)] 
为rm.fence模块添加单测
 
 ### refactor:
 
diff --git 
a/spring/src/test/java/org/apache/seata/rm/fence/FenceLogCleanRunnableUnitTest.java
 
b/spring/src/test/java/org/apache/seata/rm/fence/FenceLogCleanRunnableUnitTest.java
new file mode 100644
index 0000000000..18c63b9d42
--- /dev/null
+++ 
b/spring/src/test/java/org/apache/seata/rm/fence/FenceLogCleanRunnableUnitTest.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.seata.rm.fence;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.lang.reflect.Constructor;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * Unit tests for FenceLogCleanRunnable - Safe version without static field 
modification
+ * This test class focuses on testing the inner class without polluting global 
state
+ */
+@ExtendWith(MockitoExtension.class)
+public class FenceLogCleanRunnableUnitTest {
+
+    @Test
+    public void testFenceLogCleanRunnableExists() throws Exception {
+        // Test that the inner class exists
+        Class<?>[] innerClasses = 
SpringFenceHandler.class.getDeclaredClasses();
+        Class<?> cleanRunnableClass = null;
+
+        for (Class<?> innerClass : innerClasses) {
+            if ("FenceLogCleanRunnable".equals(innerClass.getSimpleName())) {
+                cleanRunnableClass = innerClass;
+                break;
+            }
+        }
+
+        assertNotNull(cleanRunnableClass, "FenceLogCleanRunnable inner class 
should exist");
+        assertTrue(Runnable.class.isAssignableFrom(cleanRunnableClass), 
"Should implement Runnable interface");
+    }
+
+    @Test
+    public void testFenceLogCleanRunnableInstantiation() throws Exception {
+        // Test that we can create instance of the inner class
+        Class<?>[] innerClasses = 
SpringFenceHandler.class.getDeclaredClasses();
+        Class<?> cleanRunnableClass = null;
+
+        for (Class<?> innerClass : innerClasses) {
+            if ("FenceLogCleanRunnable".equals(innerClass.getSimpleName())) {
+                cleanRunnableClass = innerClass;
+                break;
+            }
+        }
+
+        assertNotNull(cleanRunnableClass);
+
+        Constructor<?> constructor = 
cleanRunnableClass.getDeclaredConstructor();
+        constructor.setAccessible(true);
+        Object runnable = constructor.newInstance();
+
+        assertNotNull(runnable);
+        assertTrue(runnable instanceof Runnable);
+    }
+
+    @Test
+    public void testDeleteFenceMethodWithMockedStatic() {
+        // Test static deleteFence method safely using MockedStatic
+        try (MockedStatic<SpringFenceHandler> mockedStatic = 
mockStatic(SpringFenceHandler.class)) {
+            mockedStatic
+                    .when(() -> SpringFenceHandler.deleteFence("test-xid", 
123L))
+                    .thenReturn(true);
+            mockedStatic
+                    .when(() -> SpringFenceHandler.deleteFence("fail-xid", 
456L))
+                    .thenReturn(false);
+
+            // Test successful deletion
+            boolean result1 = SpringFenceHandler.deleteFence("test-xid", 123L);
+            assertTrue(result1);
+
+            // Test failed deletion
+            boolean result2 = SpringFenceHandler.deleteFence("fail-xid", 456L);
+            assertFalse(result2);
+
+            // Verify method calls
+            mockedStatic.verify(() -> 
SpringFenceHandler.deleteFence("test-xid", 123L));
+            mockedStatic.verify(() -> 
SpringFenceHandler.deleteFence("fail-xid", 456L));
+        }
+    }
+
+    @Test
+    public void testDeleteFenceWithException() {
+        // Test exception handling in static deleteFence method
+        try (MockedStatic<SpringFenceHandler> mockedStatic = 
mockStatic(SpringFenceHandler.class)) {
+            mockedStatic
+                    .when(() -> SpringFenceHandler.deleteFence("error-xid", 
789L))
+                    .thenThrow(new RuntimeException("Database error"));
+
+            // Should throw exception as expected
+            assertThrows(RuntimeException.class, () -> {
+                SpringFenceHandler.deleteFence("error-xid", 789L);
+            });
+
+            mockedStatic.verify(() -> 
SpringFenceHandler.deleteFence("error-xid", 789L));
+        }
+    }
+
+    @Test
+    public void testMultipleDeleteFenceCalls() {
+        // Test multiple static method calls in isolated environment
+        try (MockedStatic<SpringFenceHandler> mockedStatic = 
mockStatic(SpringFenceHandler.class)) {
+            mockedStatic
+                    .when(() -> SpringFenceHandler.deleteFence(anyString(), 
anyLong()))
+                    .thenReturn(true);
+
+            // Make multiple calls
+            boolean result1 = SpringFenceHandler.deleteFence("xid1", 100L);
+            boolean result2 = SpringFenceHandler.deleteFence("xid2", 200L);
+            boolean result3 = SpringFenceHandler.deleteFence("xid3", 300L);
+
+            // All should succeed
+            assertTrue(result1);
+            assertTrue(result2);
+            assertTrue(result3);
+
+            // Verify all calls were made
+            mockedStatic.verify(() -> SpringFenceHandler.deleteFence("xid1", 
100L));
+            mockedStatic.verify(() -> SpringFenceHandler.deleteFence("xid2", 
200L));
+            mockedStatic.verify(() -> SpringFenceHandler.deleteFence("xid3", 
300L));
+        }
+    }
+
+    @Test
+    public void testFenceLogIdentityInnerClass() throws Exception {
+        // Test FenceLogIdentity inner class existence and instantiation
+        Class<?>[] innerClasses = 
SpringFenceHandler.class.getDeclaredClasses();
+        Class<?> identityClass = null;
+
+        for (Class<?> innerClass : innerClasses) {
+            if ("FenceLogIdentity".equals(innerClass.getSimpleName())) {
+                identityClass = innerClass;
+                break;
+            }
+        }
+
+        assertNotNull(identityClass, "FenceLogIdentity inner class should 
exist");
+
+        // Test instantiation
+        Constructor<?> constructor = identityClass.getDeclaredConstructor();
+        constructor.setAccessible(true);
+        Object identity = constructor.newInstance();
+
+        assertNotNull(identity);
+    }
+}
diff --git 
a/spring/src/test/java/org/apache/seata/rm/fence/FenceLogIdentityTest.java 
b/spring/src/test/java/org/apache/seata/rm/fence/FenceLogIdentityTest.java
new file mode 100644
index 0000000000..85fe5e98d4
--- /dev/null
+++ b/spring/src/test/java/org/apache/seata/rm/fence/FenceLogIdentityTest.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.seata.rm.fence;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Constructor;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Unit tests for FenceLogIdentity
+ * Tests the inner class FenceLogIdentity of SpringFenceHandler
+ * This test class is completely isolated and safe from static state pollution
+ */
+public class FenceLogIdentityTest {
+
+    private Object fenceLogIdentity;
+    private Class<?> fenceLogIdentityClass;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        // Get inner class
+        Class<?>[] innerClasses = 
SpringFenceHandler.class.getDeclaredClasses();
+        for (Class<?> innerClass : innerClasses) {
+            if ("FenceLogIdentity".equals(innerClass.getSimpleName())) {
+                fenceLogIdentityClass = innerClass;
+                break;
+            }
+        }
+
+        assertNotNull(fenceLogIdentityClass, "FenceLogIdentity inner class 
should exist");
+
+        // Create an instance
+        Constructor<?> constructor = 
fenceLogIdentityClass.getDeclaredConstructor();
+        constructor.setAccessible(true);
+        fenceLogIdentity = constructor.newInstance();
+    }
+
+    @Test
+    public void testDefaultConstructor() throws Exception {
+        // Given & When
+        Constructor<?> constructor = 
fenceLogIdentityClass.getDeclaredConstructor();
+        constructor.setAccessible(true);
+        Object instance = constructor.newInstance();
+
+        // Then
+        assertNotNull(instance);
+    }
+
+    @Test
+    public void testGetXidInitiallyNull() throws Exception {
+        // Given
+        java.lang.reflect.Method getXidMethod = 
fenceLogIdentityClass.getDeclaredMethod("getXid");
+        getXidMethod.setAccessible(true);
+
+        // When
+        String xid = (String) getXidMethod.invoke(fenceLogIdentity);
+
+        // Then
+        assertNull(xid);
+    }
+
+    @Test
+    public void testGetBranchIdInitiallyNull() throws Exception {
+        // Given
+        java.lang.reflect.Method getBranchIdMethod = 
fenceLogIdentityClass.getDeclaredMethod("getBranchId");
+        getBranchIdMethod.setAccessible(true);
+
+        // When
+        Long branchId = (Long) getBranchIdMethod.invoke(fenceLogIdentity);
+
+        // Then
+        assertNull(branchId);
+    }
+
+    @Test
+    public void testSetAndGetXid() throws Exception {
+        // Given
+        String testXid = "test-xid-123";
+        java.lang.reflect.Method setXidMethod = 
fenceLogIdentityClass.getDeclaredMethod("setXid", String.class);
+        java.lang.reflect.Method getXidMethod = 
fenceLogIdentityClass.getDeclaredMethod("getXid");
+        setXidMethod.setAccessible(true);
+        getXidMethod.setAccessible(true);
+
+        // When
+        setXidMethod.invoke(fenceLogIdentity, testXid);
+        String result = (String) getXidMethod.invoke(fenceLogIdentity);
+
+        // Then
+        assertEquals(testXid, result);
+    }
+
+    @Test
+    public void testSetAndGetBranchId() throws Exception {
+        // Given
+        Long testBranchId = 123456L;
+        java.lang.reflect.Method setBranchIdMethod = 
fenceLogIdentityClass.getDeclaredMethod("setBranchId", Long.class);
+        java.lang.reflect.Method getBranchIdMethod = 
fenceLogIdentityClass.getDeclaredMethod("getBranchId");
+        setBranchIdMethod.setAccessible(true);
+        getBranchIdMethod.setAccessible(true);
+
+        // When
+        setBranchIdMethod.invoke(fenceLogIdentity, testBranchId);
+        Long result = (Long) getBranchIdMethod.invoke(fenceLogIdentity);
+
+        // Then
+        assertEquals(testBranchId, result);
+    }
+
+    @Test
+    public void testSetXidToNull() throws Exception {
+        // Given
+        java.lang.reflect.Method setXidMethod = 
fenceLogIdentityClass.getDeclaredMethod("setXid", String.class);
+        java.lang.reflect.Method getXidMethod = 
fenceLogIdentityClass.getDeclaredMethod("getXid");
+        setXidMethod.setAccessible(true);
+        getXidMethod.setAccessible(true);
+
+        // When
+        setXidMethod.invoke(fenceLogIdentity, (String) null);
+        String result = (String) getXidMethod.invoke(fenceLogIdentity);
+
+        // Then
+        assertNull(result);
+    }
+
+    @Test
+    public void testSetBranchIdToNull() throws Exception {
+        // Given
+        java.lang.reflect.Method setBranchIdMethod = 
fenceLogIdentityClass.getDeclaredMethod("setBranchId", Long.class);
+        java.lang.reflect.Method getBranchIdMethod = 
fenceLogIdentityClass.getDeclaredMethod("getBranchId");
+        setBranchIdMethod.setAccessible(true);
+        getBranchIdMethod.setAccessible(true);
+
+        // When
+        setBranchIdMethod.invoke(fenceLogIdentity, (Long) null);
+        Long result = (Long) getBranchIdMethod.invoke(fenceLogIdentity);
+
+        // Then
+        assertNull(result);
+    }
+
+    @Test
+    public void testSetAndGetMultipleValues() throws Exception {
+        // Given
+        String testXid1 = "test-xid-1";
+        String testXid2 = "test-xid-2";
+        Long testBranchId1 = 111L;
+        Long testBranchId2 = 222L;
+
+        java.lang.reflect.Method setXidMethod = 
fenceLogIdentityClass.getDeclaredMethod("setXid", String.class);
+        java.lang.reflect.Method getXidMethod = 
fenceLogIdentityClass.getDeclaredMethod("getXid");
+        java.lang.reflect.Method setBranchIdMethod = 
fenceLogIdentityClass.getDeclaredMethod("setBranchId", Long.class);
+        java.lang.reflect.Method getBranchIdMethod = 
fenceLogIdentityClass.getDeclaredMethod("getBranchId");
+
+        setXidMethod.setAccessible(true);
+        getXidMethod.setAccessible(true);
+        setBranchIdMethod.setAccessible(true);
+        getBranchIdMethod.setAccessible(true);
+
+        // When & Then - Set first group of values
+        setXidMethod.invoke(fenceLogIdentity, testXid1);
+        setBranchIdMethod.invoke(fenceLogIdentity, testBranchId1);
+
+        assertEquals(testXid1, getXidMethod.invoke(fenceLogIdentity));
+        assertEquals(testBranchId1, 
getBranchIdMethod.invoke(fenceLogIdentity));
+
+        // When & Then - Set second group of values
+        setXidMethod.invoke(fenceLogIdentity, testXid2);
+        setBranchIdMethod.invoke(fenceLogIdentity, testBranchId2);
+
+        assertEquals(testXid2, getXidMethod.invoke(fenceLogIdentity));
+        assertEquals(testBranchId2, 
getBranchIdMethod.invoke(fenceLogIdentity));
+    }
+}
diff --git 
a/spring/src/test/java/org/apache/seata/rm/fence/SpringFenceConfigTest.java 
b/spring/src/test/java/org/apache/seata/rm/fence/SpringFenceConfigTest.java
new file mode 100644
index 0000000000..f1aeb24a1a
--- /dev/null
+++ b/spring/src/test/java/org/apache/seata/rm/fence/SpringFenceConfigTest.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.seata.rm.fence;
+
+import org.apache.seata.common.exception.FrameworkErrorCode;
+import 
org.apache.seata.integration.tx.api.fence.exception.CommonFenceException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.sql.DataSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mockStatic;
+
+/**
+ * Unit tests for SpringFenceConfig
+ * Uses MockedStatic to avoid static state pollution
+ * This version is completely isolated and safe from global test pollution
+ */
+@ExtendWith(MockitoExtension.class)
+public class SpringFenceConfigTest {
+
+    @Mock
+    private DataSource dataSource;
+
+    @Mock
+    private PlatformTransactionManager transactionManager;
+
+    private SpringFenceConfig springFenceConfig;
+
+    @BeforeEach
+    public void setUp() {
+        springFenceConfig = new SpringFenceConfig(dataSource, 
transactionManager);
+    }
+
+    @Test
+    public void testConstructorWithValidParameters() {
+        // Given
+        DataSource testDataSource = dataSource;
+        PlatformTransactionManager testTransactionManager = transactionManager;
+
+        // When
+        SpringFenceConfig config = new SpringFenceConfig(testDataSource, 
testTransactionManager);
+
+        // Then
+        assertNotNull(config);
+    }
+
+    @Test
+    public void 
testAfterPropertiesSetWithValidDataSourceAndTransactionManager() {
+        // Given
+        try (MockedStatic<SpringFenceHandler> mockedStatic = 
mockStatic(SpringFenceHandler.class)) {
+            // When
+            springFenceConfig.afterPropertiesSet();
+
+            // Then
+            mockedStatic.verify(() -> 
SpringFenceHandler.setDataSource(dataSource));
+            mockedStatic.verify(() -> 
SpringFenceHandler.setTransactionTemplate(any(TransactionTemplate.class)));
+        }
+    }
+
+    @Test
+    public void testAfterPropertiesSetWithNullDataSource() {
+        // Given
+        SpringFenceConfig configWithNullDataSource = new 
SpringFenceConfig(null, transactionManager);
+
+        // When & Then
+        CommonFenceException exception = 
assertThrows(CommonFenceException.class, () -> {
+            configWithNullDataSource.afterPropertiesSet();
+        });
+
+        assertEquals(FrameworkErrorCode.DateSourceNeedInjected, 
exception.getErrcode());
+    }
+
+    @Test
+    public void testAfterPropertiesSetWithNullTransactionManager() {
+        // Given
+        SpringFenceConfig configWithNullTxManager = new 
SpringFenceConfig(dataSource, null);
+
+        try (MockedStatic<SpringFenceHandler> mockedStatic = 
mockStatic(SpringFenceHandler.class)) {
+            // When & Then
+            CommonFenceException exception = 
assertThrows(CommonFenceException.class, () -> {
+                configWithNullTxManager.afterPropertiesSet();
+            });
+
+            assertEquals(FrameworkErrorCode.TransactionManagerNeedInjected, 
exception.getErrcode());
+        }
+    }
+
+    @Test
+    public void testAfterPropertiesSetWithBothNullParameters() {
+        // Given
+        SpringFenceConfig configWithBothNull = new SpringFenceConfig(null, 
null);
+
+        // When & Then
+        CommonFenceException exception = 
assertThrows(CommonFenceException.class, () -> {
+            configWithBothNull.afterPropertiesSet();
+        });
+
+        assertEquals(FrameworkErrorCode.DateSourceNeedInjected, 
exception.getErrcode());
+    }
+}
diff --git 
a/spring/src/test/java/org/apache/seata/rm/fence/SpringFenceHandlerUnitTest.java
 
b/spring/src/test/java/org/apache/seata/rm/fence/SpringFenceHandlerUnitTest.java
new file mode 100644
index 0000000000..36e5c028d5
--- /dev/null
+++ 
b/spring/src/test/java/org/apache/seata/rm/fence/SpringFenceHandlerUnitTest.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.seata.rm.fence;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.transaction.annotation.Isolation;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.sql.DataSource;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * Unit tests for SpringFenceHandler - Safe version without static field 
modification
+ * This test class focuses on testing methods that don't require static state 
modification
+ */
+@ExtendWith(MockitoExtension.class)
+public class SpringFenceHandlerUnitTest {
+
+    @Mock
+    private DataSource dataSource;
+
+    private SpringFenceHandler springFenceHandler;
+
+    @BeforeEach
+    public void setUp() {
+        springFenceHandler = new SpringFenceHandler();
+    }
+
+    @Test
+    public void testSpringFenceHandlerInstantiation() {
+        // Test that SpringFenceHandler can be instantiated
+        SpringFenceHandler handler = new SpringFenceHandler();
+        assertNotNull(handler);
+    }
+
+    @Test
+    public void testCreateTransactionTemplateForTransactionalMethodWithNull() 
throws Exception {
+        // Test private method through reflection without modifying static 
state
+        Method createMethod = SpringFenceHandler.class.getDeclaredMethod(
+                "createTransactionTemplateForTransactionalMethod", 
Transactional.class);
+        createMethod.setAccessible(true);
+
+        // Use MockedStatic to safely test without polluting global state
+        try (MockedStatic<SpringFenceHandler> mockedStatic = 
mockStatic(SpringFenceHandler.class, CALLS_REAL_METHODS)) {
+            // Mock static method calls within this scope
+            
mockedStatic.when(SpringFenceHandler::getDataSource).thenReturn(dataSource);
+
+            // This test will verify the method works with null transactional 
annotation
+            // The actual implementation will be tested in integration tests
+            assertDoesNotThrow(() -> {
+                createMethod.invoke(springFenceHandler, (Transactional) null);
+            });
+        }
+    }
+
+    @Test
+    public void testCreateTransactionTemplateWithTransactionalAnnotation() 
throws Exception {
+        // Test with dynamic proxy for Transactional annotation
+        Transactional transactional = (Transactional) 
java.lang.reflect.Proxy.newProxyInstance(
+                Transactional.class.getClassLoader(), new Class[] 
{Transactional.class}, (proxy, method, args) -> {
+                    if ("isolation".equals(method.getName())) {
+                        return Isolation.READ_COMMITTED;
+                    }
+                    return method.getDefaultValue();
+                });
+
+        Method createMethod = SpringFenceHandler.class.getDeclaredMethod(
+                "createTransactionTemplateForTransactionalMethod", 
Transactional.class);
+        createMethod.setAccessible(true);
+
+        // Test that method works properly - need to handle potential 
exceptions carefully
+        try {
+            Object result = createMethod.invoke(springFenceHandler, 
transactional);
+            // The method should return a TransactionTemplate or throw an 
exception
+            // We just verify that the invocation doesn't cause unexpected 
errors
+            assertNotNull(result, "Method should return a result or throw a 
specific exception");
+        } catch (java.lang.reflect.InvocationTargetException e) {
+            // If the method throws an exception, it should be a known type
+            Throwable cause = e.getCause();
+            // For this test, we accept that the method might throw exceptions 
due to missing dependencies
+            // The important thing is that the method is accessible and the 
annotation is processed
+            assertTrue(
+                    cause instanceof RuntimeException || cause instanceof 
IllegalArgumentException,
+                    "Expected runtime exception due to missing dependencies, 
but got: "
+                            + cause.getClass().getName());
+        }
+    }
+
+    @Test
+    public void testStaticMethodsWithMockedStatic() {
+        // Test static methods safely using MockedStatic
+        try (MockedStatic<SpringFenceHandler> mockedStatic = 
mockStatic(SpringFenceHandler.class)) {
+            
mockedStatic.when(SpringFenceHandler::getDataSource).thenReturn(dataSource);
+            mockedStatic
+                    .when(() -> SpringFenceHandler.deleteFence("test", 123L))
+                    .thenReturn(true);
+
+            // Test static method calls within mocked scope
+            DataSource result = SpringFenceHandler.getDataSource();
+            boolean deleteResult = SpringFenceHandler.deleteFence("test", 
123L);
+
+            assertSame(dataSource, result);
+            assertTrue(deleteResult);
+
+            // Verify interactions
+            mockedStatic.verify(SpringFenceHandler::getDataSource);
+            mockedStatic.verify(() -> SpringFenceHandler.deleteFence("test", 
123L));
+        }
+        // MockedStatic automatically restores original behavior after 
try-with-resources
+    }
+
+    @Test
+    public void testMultipleStaticMethodCalls() {
+        // Test multiple static method calls in isolated scope
+        try (MockedStatic<SpringFenceHandler> mockedStatic = 
mockStatic(SpringFenceHandler.class)) {
+            mockedStatic
+                    .when(() -> SpringFenceHandler.deleteFence(anyString(), 
anyLong()))
+                    .thenReturn(true);
+
+            boolean result1 = SpringFenceHandler.deleteFence("xid1", 100L);
+            boolean result2 = SpringFenceHandler.deleteFence("xid2", 200L);
+
+            assertTrue(result1);
+            assertTrue(result2);
+
+            mockedStatic.verify(() -> SpringFenceHandler.deleteFence("xid1", 
100L));
+            mockedStatic.verify(() -> SpringFenceHandler.deleteFence("xid2", 
200L));
+        }
+    }
+
+    @Test
+    public void testInstanceMethodsOnly() {
+        // Test that we can create instances without static dependency issues
+        SpringFenceHandler handler1 = new SpringFenceHandler();
+        SpringFenceHandler handler2 = new SpringFenceHandler();
+
+        assertNotNull(handler1);
+        assertNotNull(handler2);
+        assertNotSame(handler1, handler2);
+    }
+
+    @Test
+    public void testFenceLogIdentityInnerClass() throws Exception {
+        // Test the inner class without modifying static state
+        Class<?>[] innerClasses = 
SpringFenceHandler.class.getDeclaredClasses();
+        Class<?> fenceLogIdentityClass = null;
+
+        for (Class<?> innerClass : innerClasses) {
+            if ("FenceLogIdentity".equals(innerClass.getSimpleName())) {
+                fenceLogIdentityClass = innerClass;
+                break;
+            }
+        }
+
+        assertNotNull(fenceLogIdentityClass, "FenceLogIdentity inner class 
should exist");
+
+        // Test that we can instantiate the inner class - need to make 
constructor accessible
+        Constructor<?> constructor = 
fenceLogIdentityClass.getDeclaredConstructor();
+        constructor.setAccessible(true); // Make private constructor accessible
+        Object identity = constructor.newInstance();
+        assertNotNull(identity);
+    }
+
+    @Test
+    public void testFenceLogCleanRunnableInnerClass() throws Exception {
+        // Test the inner class without modifying static state
+        Class<?>[] innerClasses = 
SpringFenceHandler.class.getDeclaredClasses();
+        Class<?> cleanRunnableClass = null;
+
+        for (Class<?> innerClass : innerClasses) {
+            if ("FenceLogCleanRunnable".equals(innerClass.getSimpleName())) {
+                cleanRunnableClass = innerClass;
+                break;
+            }
+        }
+
+        assertNotNull(cleanRunnableClass, "FenceLogCleanRunnable inner class 
should exist");
+
+        // Test that we can instantiate the inner class - need to make 
constructor accessible
+        Constructor<?> constructor = 
cleanRunnableClass.getDeclaredConstructor();
+        constructor.setAccessible(true); // Make private constructor accessible
+        Object runnable = constructor.newInstance();
+        assertNotNull(runnable);
+        assertTrue(runnable instanceof Runnable);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to