Spring Cloud体系下,使用Junit 5、MyBati

2024-02-17  本文已影响0人  听歌闭麦开始自闭

情况说明

在使用Spring Cloud体系时,Spring Boot 项目的启动会伴随着诸多第三方技术的客户侧/生产侧开始工作,
例如Dubbo、Redis、Jetcd、Nacos、Zookeeper等服务,会去主动的完成注册、连接、发送心跳等行为。

这些操作,对于单元测试而言是没有必要的,单元测试的核心原则不考虑这些内容。
通常情况下,即使有需求,对于外部服务的调用也是通过Mock的形式,主动模拟外部接口的调用返回;
但有些情况下,这种模拟本身就变得不正确了。

例如,程序通过AOP、MyBatis插件的形式配合完成的SQL行级数据权限拼接,在这种情况下,SQL的完全体是不能预先获知的(实际上可以,但很麻烦),
因此单元测试必须集成Spring、内存数据库、MyBatis (Plus)技术,完成对已有代码的的最小粒度测试。

在上述案例的情况下,这个测试本身的目的 仍然是为了验证 Mapper/Dao 层的最终SQL是否可以正确执行,因此是符合横向单层测试的理念的,只是为了达到这个目的需要借助纵向穿透测试的使用,在我看来,这仍属于单元测试的范畴。

代码示例

@TestConfiguration
public class MyBatisTestConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .build();
    }

    @Bean
    public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScript(new ClassPathResource("sql/schemas-h2.sql"));
        populator.addScript(new ClassPathResource("sql/data-h2.sql"));

        DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
        dataSourceInitializer.setDataSource(dataSource);
        dataSourceInitializer.setDatabasePopulator(populator);
        dataSourceInitializer.setEnabled(true);
        return dataSourceInitializer;
    }

    @Bean(name = "h2WebServer", initMethod = "start", destroyMethod = "stop")
    public Server server() throws Exception {
        return Server.createWebServer("-web", "-webAllowOthers", "-webDaemon", "-webPort", "8082");
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setTypeAliasesPackage("xxx.xxx.xxx.xxx.entity");

        Configuration configuration = new Configuration();
        configuration.setCacheEnabled(false);
        configuration.setCallSettersOnNulls(true);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setLogImpl(StdOutImpl.class);
        sessionFactory.setConfiguration(configuration);

        return sessionFactory.getObject();
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("xxx.xxx.xxx.xxx.mapper");
        configurer.setAnnotationClass(Mapper.class);
        configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        return configurer;
    }
}

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = {
        MyBatisTestConfig.class, IDemoMapper.class, IDemoService.class
})
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ExtendWith(MockitoExtension.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class IDemoServiceTest {
    @Autowired
    private IDemoService iDemoService;

    @Test
    void test() {
        Demo entity = iDemoService.selectById(1);
        Assertions.assertNotNull(entity);
        Assertions.assertEquals(1L, contact.getId());
    }
}

如果需要额外的Bean,在 @SpringBootTest 的classes中不断追加即可。

上一篇下一篇

猜你喜欢

热点阅读