Spring Boot Starter for MyBatis integration providing auto-configuration and dependency management
—
The MyBatis Spring Boot Starter provides specialized testing support through test slice annotations that enable focused testing of MyBatis components without loading the full Spring application context.
Main test slice annotation for MyBatis-focused integration testing.
/**
* Test slice annotation for MyBatis components. Loads only MyBatis-relevant
* configuration and uses an embedded test database by default.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(MybatisTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(MybatisTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureMybatis
@AutoConfigureTestDatabase
@ImportAutoConfiguration
public @interface MybatisTest {
/**
* Properties to add to the Spring Environment before the test runs
* @return the properties to add
*/
String[] properties() default {};
/**
* Determines if default filtering should be used with @SpringBootApplication
* @return if default filters should be used
*/
boolean useDefaultFilters() default true;
/**
* Include filters for adding otherwise filtered beans to the application context
* @return include filters to apply
*/
Filter[] includeFilters() default {};
/**
* Exclude filters for filtering beans that would otherwise be added
* @return exclude filters to apply
*/
Filter[] excludeFilters() default {};
/**
* Auto-configuration exclusions that should be applied for this test
* @return auto-configuration exclusions to apply
*/
@AliasFor(annotation = ImportAutoConfiguration.class, attribute = "exclude")
Class<?>[] excludeAutoConfiguration() default {};
}Usage Examples:
@MybatisTest
class UserMapperTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserMapper userMapper;
@Test
void testFindById() {
// Given
User user = new User("John", "john@example.com");
entityManager.persistAndFlush(user);
// When
User found = userMapper.findById(user.getId());
// Then
assertThat(found.getName()).isEqualTo("John");
assertThat(found.getEmail()).isEqualTo("john@example.com");
}
@Test
void testInsert() {
// Given
User user = new User("Jane", "jane@example.com");
// When
userMapper.insert(user);
// Then
assertThat(user.getId()).isNotNull();
User found = entityManager.find(User.class, user.getId());
assertThat(found.getName()).isEqualTo("Jane");
}
}Lower-level annotation for including MyBatis auto-configuration in custom test slices.
/**
* Auto-configuration imports for typical MyBatis tests.
* Most tests should use @MybatisTest instead of this annotation directly.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ImportAutoConfiguration
public @interface AutoConfigureMybatis {
// No additional attributes - provides standard MyBatis auto-configuration
}Usage Examples:
@DataJpaTest
@AutoConfigureMybatis
class MixedRepositoryTest {
@Autowired
private JpaUserRepository jpaUserRepository;
@Autowired
private UserMapper userMapper;
@Test
void testJpaAndMyBatisIntegration() {
// Test both JPA and MyBatis in the same test
User user = new User("Alice", "alice@example.com");
jpaUserRepository.save(user);
List<User> users = userMapper.findAll();
assertThat(users).hasSize(1);
assertThat(users.get(0).getName()).isEqualTo("Alice");
}
}@MybatisTest automatically configures an embedded test database:
@MybatisTest
class DatabaseTest {
// Automatically uses H2 embedded database
// No additional configuration required
}
// Override test database configuration
@MybatisTest
@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.DERBY)
class DerbyDatabaseTest {
// Uses Derby instead of H2
}
// Use real database in tests
@MybatisTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class RealDatabaseTest {
// Uses actual database configuration from application properties
}Tests are automatically wrapped in transactions and rolled back:
@MybatisTest
class TransactionalTest {
@Autowired
private UserMapper userMapper;
@Test
void testInsertRollback() {
User user = new User("Test", "test@example.com");
userMapper.insert(user);
// This will be rolled back after the test
assertThat(userMapper.findById(user.getId())).isNotNull();
}
@Test
@Commit // Override rollback behavior
void testInsertCommit() {
User user = new User("Committed", "commit@example.com");
userMapper.insert(user);
// This will be committed
}
}Configure test-specific properties:
@MybatisTest(properties = {
"mybatis.configuration.map-underscore-to-camel-case=true",
"mybatis.configuration.cache-enabled=false",
"logging.level.org.mybatis=DEBUG"
})
class CustomConfigTest {
// Test with custom MyBatis configuration
}Control which components are loaded in tests:
@MybatisTest(
includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class),
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)
)
class FilteredComponentTest {
// Includes @Service components but excludes @Controller components
}@MybatisTest
@Import(TestMyBatisConfiguration.class)
class CustomConfigurationTest {
@TestConfiguration
static class TestMyBatisConfiguration {
@Bean
@Primary
public ConfigurationCustomizer testConfigurationCustomizer() {
return configuration -> {
configuration.addInterceptor(new TestInterceptor());
configuration.setCallSettersOnNulls(true);
};
}
}
@Autowired
private UserMapper userMapper;
@Test
void testWithCustomConfiguration() {
// Test with custom configuration
}
}@MybatisTest
class MockIntegrationTest {
@Autowired
private UserMapper userMapper;
@MockBean
private EmailService emailService;
@Test
void testUserCreationWithEmailService() {
User user = new User("John", "john@example.com");
userMapper.insert(user);
// Mock behavior
when(emailService.sendWelcomeEmail(any())).thenReturn(true);
// Test integration
assertThat(userMapper.findById(user.getId())).isNotNull();
verify(emailService, never()).sendWelcomeEmail(any()); // Just an example
}
}@MybatisTest
class MultipleMapperTest {
@Autowired
private UserMapper userMapper;
@Autowired
private OrderMapper orderMapper;
@Test
void testUserOrderRelationship() {
// Create user
User user = new User("John", "john@example.com");
userMapper.insert(user);
// Create order for user
Order order = new Order(user.getId(), "Product A", 99.99);
orderMapper.insert(order);
// Test relationship
List<Order> userOrders = orderMapper.findByUserId(user.getId());
assertThat(userOrders).hasSize(1);
assertThat(userOrders.get(0).getProduct()).isEqualTo("Product A");
}
}@MybatisTest(properties = {
"mybatis.configuration.cache-enabled=true",
"logging.level.org.mybatis=TRACE"
})
class PerformanceTest {
@Autowired
private UserMapper userMapper;
@Test
void testBatchInsert() {
List<User> users = IntStream.range(0, 1000)
.mapToObj(i -> new User("User" + i, "user" + i + "@example.com"))
.collect(Collectors.toList());
StopWatch stopWatch = new StopWatch();
stopWatch.start();
users.forEach(userMapper::insert);
stopWatch.stop();
assertThat(stopWatch.getTotalTimeMillis()).isLessThan(5000);
assertThat(userMapper.count()).isEqualTo(1000);
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-mybatis-spring-boot--mybatis-spring-boot-starter