【问题标题】:Can't Autowire Service in JUnit 4 Test in Spring Boot Multi Module Application无法在 Spring Boot 多模块应用程序中的 JUnit 4 测试中自动装配服务
【发布时间】:2020-04-30 08:49:51
【问题描述】:

我有以下项目结构:

-module1
--src/main/java/at.flobau.demo.module1
---model
----Product.java
---service
----ProductService.java
---TestConfiguration.java

--src/test/java/at.flobau.demo.module1.service
---ProductServiceTest.java

-module2
--src/main/java/at.flobau.demo.main
---MainApplication.java

Application 类如下所示:

@SpringBootApplication(scanBasePackages = {"at.flobau.demo.main"})
@PropertySource(value = "classpath:application.properties")
@EnableJpaRepositories("at.flobau.demo.module1")
@EntityScan(basePackages = {"at.flobau.demo.module1"})
public class PocApplication {

    public static void main(String[] args) {
        SpringApplication.run(PocApplication.class, args);
    }

}

服务如下所示:

@Service
public class ProductService implements IProductService {

    @Autowired
    private IProductRepository productRepository;

    ...
}

测试类如下所示:

@SpringBootTest
@ContextConfiguration(classes = { TestConfiguration.class }, loader = 
AnnotationConfigContextLoader.class)
@RunWith(SpringRunner.class)
public class ProductServiceTest {

    @Autowired
    private ProductService productService;

    ...
}

测试配置文件如下所示:

@Configuration
@ComponentScan("at.flobau.demo")
public class TestConfiguration{ }

IntelliJ 告诉我,测试中的 ProductService 无法自动装配。当我运行测试时,我得到一个异常:

Error creating bean with name 'ProductServiceTest': Unsatisfied dependency expressed through field 
'productService'; nested exception is 
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 
'at.flobau.demo.module1.products.service.ProductService' available: expected at least 1 bean which 
qualifies as autowire candidate. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

【问题讨论】:

  • 我得到了一个示例应用程序,其中包含使用 mockito github.com/naveenkulkarni029/products-api 的 junit 测试用例程序
  • 尝试将 ProductService 的包名显式添加到配置类中的 @ComponentScan("at.flobau.demo") 中
  • 主类在module2中,所以module1独立不是spring boot应用程序,尝试将@SpringBootConfiguration添加到你的测试配置中。 [stackoverflow.com/questions/39858226/… 参考这个答案。

标签: java spring spring-boot junit


【解决方案1】:

您应该避免使用字段注入(即使是可能的)并使用构造函数注入。这将解决这个问题,因为您将能够从构造函数传递服务,但它在未来也很有用,因为您可以比“隐藏”的字段注入更好地在代码中定位用法和跟踪对象

所以我建议不要在这里尝试解决您的问题,而是在构造函数注入中重构您的类并通过直接在测试中创建对象或通过为您的测试创建将生成对象的配置来传递服务给出它需要的论点

类似

@ContextConfiguration(classes = { GeneralTester.TestConfig.class })
@RunWith(SpringRunner.class)
public class GeneralTester {
  @TestConfiguration
  public static class TestConfig {
    @Bean
    public IProductService productService(final IProductRepository productRepository){
     return new ProductService(productRepository);
    }
    @Bean
    public IProductRepository productRepository(){
      return mock(IProductRepository.class);
    }
  }

  @Autowire
  public IProductService productService;

  @Autowire
  public IProductRepository productRepository;

  @Before
  public void setUp() {
    reset(productRepository);
  }

  @After
  public void tearDown() {
    verifyNoMoreInteractions(productRepository);
  }

  @Test
  public void doSmth() {
    //... your setup
    when(productRepository.save(any())).thenReturn("something");
    //... your call and assertions
    verify(productRepository).save(any());
  }
}

【讨论】:

  • 感谢您的回答。但是我的 ProductService 没有参数,所以我不能这样实现。
  • 是的,我看到它没有参数,但我的建议是重构它并使用带参数的构造函数,而不是使用 @Bioaim 的字段注入
  • 另外我刚刚意识到你正在做一个单元测试并且你有@SpringBootTest。这不是必需的,因为它只会使您的测试减慢很多(而不是半秒,这将花费您的服务器启动所需的时间..)单元测试不应该要求服务器运行。因此我的测试示例没有@SpringBootTest
  • 好的,现在明白了。我现在确实收到此错误:Invalid bean definition with name 'productService' defined in class path resource [at/flobau/demo/products/service/ProductServiceTest$TestConfig.class]: @Bean definition illegally overridden by existing bean definition
  • 我需要查看您的代码,因为这意味着您错过了一个小细节。也许试试 pastebin ?
【解决方案2】:

你可以用@SpringBootTest(classes = ProductService.class)注释你的测试类

【讨论】:

  • 我得到了这个:原因:org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'de.esag.tyr.poc.products.service.IProductRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
  • 仔细阅读。它试图在其中创建一个 IProductRepository bean。尝试使用注释 @MockBean 模拟它。
【解决方案3】:

您是否尝试过在测试配置类中创建服务的 bean?

@TestConfiguration
@ComponentScan("at.flobau.demo")
public class TestConfiguration { 
    @Bean
    public ProductService productService() {
        return new ProductService();
    }
}

【讨论】:

  • 在创建配置时进行测试时,您应该使用@TestConfiguration 注释。只是一个建议
猜你喜欢
  • 2017-02-25
  • 2020-02-09
  • 2018-04-15
  • 2020-03-24
  • 1970-01-01
  • 2018-03-28
  • 2018-04-01
  • 2015-03-03
  • 1970-01-01
相关资源
最近更新 更多