首页 文章

如何在测试期间修改静态私有字段?

提问于
浏览
1

我的项目使用 JUnitMockitoPowerMockito 来创建单元测试 . 代码如下:

public class FirstController {
    public void doSomething() {
        ServiceExecutor.execute();
    }
}

public class ServiceExecutor {

    private static final List<Service> services = Arrays.asList(
        new Service1(),
        new Service2(),
        ...
    );

    public static void execute() {
        for (Service s : services) {
            s.execute();
        }
    }   
}

@RunWith(PowerMockRunner.class)
@PrepareForTest({ServiceExecutor.class})
public class FirstControllerTest {

        @Before
        public void prepareForTest() {
            PowerMockito.mockStatic(ServiceExecutor.class);
            PowerMockito.doNothing().when(ServiceExecutor.class)
        }

        @Test
        public void doSomethingTest() {
            FirstController firstController = new FirstController();
            firstController.doSomething();
            PowerMockito.verifyStatic(ServiceExecutor.class, Mockito.times(1));
        }   
    }

我想验证运行的 ServiceExecutor.execute() 方法 .

当调用 execute() 方法时,我试图模拟 ServiceExecutordoNothing() . 但我在 ServiceExecutor 中的 private static final List<Service> services 有问题 . 它始终为每个服务构造新实例 . 每个服务都需要更长的时间来创建新实例,如果我模拟每个 Service ,我不知道他们以后会有多少服务 .

您是否有任何想法在 FirstController 中验证 ServiceExecutor.execute() 而无需在 ServiceExecutor 中运行任何方法?

1 回答

  • 0

    所以你知道如何模拟ServiceExecutor.execute,但你不想模仿它 . 您希望在测试中执行它,但不在测试中运行所有service.execute()方法 . 这不是对FirstController的测试,而是对ServiceExecutor的测试 . 所以你可以减少你的问题 .

    您可以使用Reflection在测试中更改私有静态字段ServiceExecutor.services的值,如下所述:Change private static final field using Java reflection

    public class ServiceExecutorTest {
    
        @Test
        public void doSomethingTest() throws NoSuchFieldException, IllegalAccessException {
            Field field = null;
            List<Service> oldList = null;
            try {
                field = ServiceExecutor.class.getDeclaredField("services");
                field.setAccessible(true);
                Field modifiersField = Field.class.getDeclaredField("modifiers");
                modifiersField.setAccessible(true);
                modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    
                final Service serviceMock1 = mock(Service.class);
                final Service serviceMock2 = mock(Service.class);
                final List<Service> serviceMockList = Arrays.asList(serviceMock1, serviceMock2);
                oldList = (List<Service>) field.get(null);
                field.set(null, serviceMockList);
                ServiceExecutor.execute();
                verify(serviceMock1, times(1)).execute();
                verify(serviceMock2, times(1)).execute();
            } finally {
                // restore original value
                if (field != null && oldList != null) {
                    field.set(null, oldList);
                }
            }
        }
    
        static class Service {
            void execute() {
                throw new RuntimeException("Should not execute");
            }
        }
    
        static class ServiceExecutor {
    
            private static final List<Service> services = Arrays.asList(
                    new Service());
    
            public static void execute() {
                for (Service s : services) {
                    s.execute();
                }
            }
        }
    }
    

相关问题