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 配置,应用程序将使用我们创建的自动配置连接到名为 myDbmysql 数据库。

连接字符串包含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

禁用自动配置类

如果我们不想加载自动配置,我们可以在配置类中添加带有excludeexcludeName 属性的@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

Spring Boot / JUnit,为多个配置文件运行所有单元测试

(转)Spring Boot Junit单元测试

spring boot 1

Spring Boot 单元测试示例

spring boot单元测试spring context重复加载问题