Why component scanning does not work for Spring Boot unit tests?

后端 未结 3 875
借酒劲吻你
借酒劲吻你 2021-01-13 19:20

The service class FooServiceImpl is annotated with @Service aka @Component which makes it eligible for autowiring. Why this class is not being pick

3条回答
  •  無奈伤痛
    2021-01-13 19:53

    I had to solve a similar problem with a slight variation. Thought to share the details of that, thinking it might give choices to those who hit upon similar issues.

    I wanted to write integration tests with only necessary dependencies loaded up instead of all of the app dependencies. So I chose to use @DataJpaTest, instead of @SpringBootTest. And, I had to include @ComponentScan too to parse the @Service beans. However, the moment ServiceOne started using a mapper bean from another package, I had to specify the specific packages to be loaded with @ComponentScan. Surprisingly, I even had to do this for the second service that does not auto-wire this mapper. I did not like that because it leaves the impression to the reader that this service depends on that mapper when it is actually not. So I realized that the package structure for services needs to be fine-tuned further to represent the dependencies more accurately.

    To summarise, instead of @SpringBootTest, a combination of @DataJpaTest+@ComponentScan with package names can use to load just the layer-specific dependencies. This might even help us to fine-tune the design to represent your dependencies more accurately.

    Design before

    1. com.java.service.ServiceOneImpl

    @Service
    public class ServiceOneImpl implements ServiceOne {   
      @Autowired
      private RepositoryOne repositoryOne;    
      @Autowired
      private ServiceTwo serviceTwo;      
      @Autowired
      private MapperOne mapperOne;
    }
    

    2. com.java.service.ServiceTwoImpl

    @Service
    public class ServiceTwoImpl implements ServiceTwo {   
      @Autowired
      private RepositoryTwo repositoryTwo;    
    }
    

    3. ServiceOneIntegrationTest

    @RunWith(SpringRunner.class)
    @DataJpaTest
    @ComponentScan({"com.java.service","com.java.mapper"})
    public class ServiceOneIntegrationTest {
    

    4. ServiceTwoIntegrationTest.java

    @RunWith(SpringRunner.class)
    @DataJpaTest
    @ComponentScan({"com.java.service","com.java.mapper"})
    public class ServiceTwoIntegrationTest {
    

    After fine-tuning the package names

    1. com.java.service.one.ServiceOneImpl

    @Service
    public class ServiceOneImpl implements ServiceOne {   
      @Autowired
      private RepositoryOne repositoryOne;    
      @Autowired
      private ServiceTwo serviceTwo;      
      @Autowired
      private MapperOne mapperOne;
    }
    

    2. com.java.service.two.ServiceTwoImpl

    @Service
    public class ServiceTwoImpl implements ServiceTwo {   
      @Autowired
      private RepositoryTwo repositoryTwo;    
    }
    

    3. ServiceOneIntegrationTest

    @RunWith(SpringRunner.class)
    @DataJpaTest
    @ComponentScan({"com.java.service","com.java.mapper"})
    public class ServiceOneIntegrationTest {
    

    4. ServiceTwoIntegrationTest.java

    @RunWith(SpringRunner.class)
    @DataJpaTest
    @ComponentScan({"com.java.service.two"}) // CHANGE in the packages
    public class ServiceTwoIntegrationTest {
    

提交回复
热议问题