欢迎来到淼淼之森的博客小站。  交流请加我微信好友: studyjava。  也欢迎关注同名公众号:Java学习之道

单元测试:如何覆盖一个实现了Runnable或Callable的内部类

  |   0 评论   |   0 浏览

背景

假如有这样一个类:

@Component
public class TaskExecutorService {

    // 内部类实现Callable接口
    public static class StringCallableExample implements Callable<String> {

        @Autowired
        private SomeService someService;

        @Override
        public String call() throws Exception {
             someService.performAction();
             return "success";
        }
    }
}

@Component
class SomeService {
    public String performAction() {
        // 执行一些业务逻辑
        return "Service Action Performed";
    }
}

需要单测覆盖验证其中内部类的 call() 方法,直接使用 @Mock 模拟注入内部类中的组件,会出现空指针异常!

解决方案

为了测试这个实现 Callable 的内部类,我们可以创建该内部类的实例,并通过调用它的 call() 方法来执行单元测试。

首先:我们需要模拟SomeService,然后注入到TaskExecutorService.StringCallableExample的实例中。

其次:为了注入模拟的服务,需要使用反射获取StringCallableExample内部类中名为someService的字段,并设置它为可访问,然后将模拟的SomeService实例注入到这个字段中。因为内部类中 @Autowired 注解注入的组件直接使用 @Mock 会出现空指针异常,因为模拟注入不成功。

以下是如何覆盖 TaskExecutorService.StringCallableExample 的单元测试,流程示例:

  • 创建SomeService的模拟实例。
  • 创建 TaskExecutorService.StringCallableExample 的实例。
  • 使用反射技术将模拟的SomeService注入到StringCallableExample实例中。(此示例中使用的 injectMockInnerClassService 方法)
  • 调用 StringCallableExamplecall() 方法并验证期望的行为。

代码示例:

这是实现单元测试的代码示例:

@RunWith(MockitoJUnitRunner.Silent.class)
public class TaskExecutorServiceTest {

    @InjectMocks
    private TaskExecutorService taskExecutorService;

    @Mock
    private SomeService mockSomeService;


    @Before
    public void setUp() throws Exception {

    }

    /**
     * 内部类的组件注入
     */
    private void injectMockInnerClassService(TaskExecutorService.StringCallableExample innerClass) {
        try {
	        // 使用反射将mockSomeService注入到StringCallable实例中
	        java.lang.reflect.Field someServiceField = innerClass.getClass().getDeclaredField("someService");
	        someServiceField.setAccessible(true);
	        someServiceField.set(innerClass, mockSomeService);
        } catch (Exception e) {
            throw new RuntimeException("注入模拟对象失败", e);
        }
    }

    @Test
    public void testTaskExecutorService() throws Exception {
        TaskExecutorService.StringCallableExample stringCallableInnerClass = new TaskExecutorService.StringCallableExample();
	
	// 利用反射技术注入内部类使用的组件,避免注入失败引起的空指针异常
	injectMockInnerClassService(stringCallableInnerClass);

        // 安排
        when(mockSomeService.performAction()).thenReturn("Service Action Performed");

        // 动作
        String result = stringCallableInnerClass.call();

        // 断言
        assertEquals("success", result);

        // 验证
        verify(mockSomeService).performAction();
    }
}

标题:单元测试:如何覆盖一个实现了Runnable或Callable的内部类
作者:mmzsblog
地址:https://www.mmzsblog.cn/articles/2023/12/25/1703488352038.html

如未加特殊说明,文章均为原创,转载必须注明出处。均采用CC BY-SA 4.0 协议

本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。若本站转载文章遗漏了原文链接,请及时告知,我们将做删除处理!文章观点不代表本网站立场,如需处理请联系首页客服。
• 网站转载须在文章起始位置标注作者及原文连接,否则保留追究法律责任的权利。
• 公众号转载请联系网站首页的微信号申请白名单!

个人微信公众号 ↓↓↓                 

微信搜一搜 Java 学习之道