Spring Boot:在单元测试中用一个覆盖多个bean
Posted
技术标签:
【中文标题】Spring Boot:在单元测试中用一个覆盖多个bean【英文标题】:Spring Boot: Override multiple beans with one in unit-test 【发布时间】:2017-12-24 19:21:21 【问题描述】:我的项目中有一些Repository
-beans。我将此存储库的集合连接到我的一些服务,并从它们中的每一个迭代获取数据。但是在我的单元测试中,我想从 Spring 上下文中排除所有这些存储库(真正的实现)并且只使用假的。如何实现?
【问题讨论】:
【参考方案1】:测试自动配置:
让我们创建一个非常简单的示例来测试我们的自动配置。我们将创建一个名为 MyUser 的实体类,以及一个使用 Spring Data 的 MyUserRepository 接口:
@Entity
public class MyUser
@Id
private String email;
// standard constructor, getters, setters
public interface MyUserRepository
extends JpaRepository<MyUser, String>
要启用自动配置,我们可以使用@SpringBootApplication
或@EnableAutoConfiguration
注释之一:
@SpringBootApplication
public class AutoconfigurationApplication
public static void main(String[] args)
SpringApplication.run(AutoconfigurationApplication.class, args);
接下来,让我们编写一个保存 MyUser 实体的 JUnit 测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(
classes = AutoconfigurationApplication.class)
@EnableJpaRepositories(
basePackages = "com.baeldung.autoconfiguration.example" )
public class AutoconfigurationTest
@Autowired
private MyUserRepository userRepository;
@Test
public void whenSaveUser_thenOk()
MyUser user = new MyUser("user@email.com");
userRepository.save(user);
由于我们尚未定义 DataSource 配置,应用程序将使用我们创建的自动配置连接到名为 myDb
的 mysql 数据库。
连接字符串包含createDatabaseIfNotExist=true
属性,因此数据库不需要存在。但是,需要创建用户 mysqluser 或通过 mysql.user 属性指定的用户(如果存在)。
我们可以查看应用程序日志,查看 MySQL 数据源是否被使用:
web - 2017-04-12 00:01:33,956 [main] INFO o.s.j.d.DriverManagerDataSource - Loaded JDBC driver: com.mysql.cj.jdbc.Driver
禁用自动配置类
如果我们不想加载自动配置,我们可以在配置类中添加带有exclude
或excludeName
属性的@EnableAutoConfiguration
注释:
@Configuration
@EnableAutoConfiguration(
exclude=MySQLAutoconfiguration.class)
public class AutoconfigurationApplication
//...
禁用特定自动配置的另一个选项是设置spring.autoconfigure.exclude
属性:
spring.autoconfigure.exclude=com.baeldung.autoconfiguration.MySQLAutoconfiguration
资源链接:Create a Custom Auto-Configuration with Spring Boot
解决方案#2:
Matt C在本教程中也给出了解决方案:How to exclude *AutoConfiguration classes in Spring Boot JUnit tests?。
【讨论】:
【参考方案2】:Spring 上下文在单元测试中确实很少使用。您应该问自己的第一个问题:“我要测试什么工作单元?”。得到答案后,应隔离进行测试。您在这里不需要弹簧上下文。集成测试中通常需要 Spring 上下文。单元测试不能依赖于上下文。
您可以使用Mockito
提供的@Mock
和@InjectMocks
注释。例如:
public class SomeServiceTest
@InjectMocks
SomeService someService;
@Mock
PersonRepository personRepository;
@Before
public void setUp()
MockitoAnnotations.initMocks(this);
@Test
public void testFindPersonExpectOk()
String name = "John";
String secondName = "Doe";
// Configure the behavior for mocked repository
Person person = new Person(name, secondName);
when(personRepository.findByNameAndSecondName(name,
secondName).thenReturn(person);
// Call some method in testing service
Person fetchedPerson = someService.findUser(name, secondName);
// Check that everything is fine
assertThat(fetchedPerson.getName, is(name));
【讨论】:
【参考方案3】:解决办法如下:
@SpringBootApplication
@ComponentScan(basePackages = "my.base.package",
excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "my.base.package.repositories.*.*"))
public class TestApplication
public static void main(String[] args)
SpringApplication.run(TestApplication.class, args);
@Bean
public Repository someFakeRepository()
return new FakeRepository();
然后是测试类:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class ApplicationTests
@Autowired
private Repository fakeRepository;
// tests
所以我已经用测试豆替换了所有真正的豆子。
【讨论】:
以上是关于Spring Boot:在单元测试中用一个覆盖多个bean的主要内容,如果未能解决你的问题,请参考以下文章
Spring-Boot 单元测试:ConstraintValidator 中的@Value