4

I'm starting to learn both Java and Spring boot now, and I'm having some problems with dependency injection in integration tests. I have a class under src/main/java/com/rfd/domain/services called TransactionService, which is marked as @Service and which has another dependencies, one of them a repository created by Spring boot. When I launch the application, it is launched correctly so I assume the dependencies are being resolved correctly. This is the summarized class:

package com.rfd.domain.services; import allNeededImports @Service public class TransactionsService { @Autowired private KambiTransactionRepository kambiTransactionRepository; @Autowired private TransactionFactory transactionFactory; public List<Transaction> retrieveTransactions(String couponExternalId) throws InvalidTransactionException { // someCode } } 

and now, I have a TransactionsServiceTests class under /src/test/java/com/rfd/integrationtests/domain/services:

package com.rfd.integrationtests.domain.services; import allNeededImports @RunWith(SpringRunner.class) @SpringBootTest(classes = Main.class) @DataMongoTest @TestPropertySource(locations = "classpath:application-integrationtest.properties") public class TransactionsServiceTests { @Autowired private TransactionsService transactionsService; @Test public void retrieveTransactions_happyPathMultipleTransactions_transactionsRetrieved() throws InvalidTransactionException { // test code } 

When I try to launch the tests, I receive the following error:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.rfd.domain.services.TransactionsService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

I have tried to create my own @TestConfiguration class, in which I create a method marked with @Bean and returning a new instance of TransactionService, and it works. However, the error now is for the KambiTransactionRepository dependency, and I don't have an implementation of it because it is given by spring boot:

package com.rfd.infrastructure.repositories; import com.rfd.infrastructure.models.KambiTransaction; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface KambiTransactionRepository extends MongoRepository<KambiTransaction, String> { List<KambiTransaction> findByCouponRef(String couponRef); } 

QUESTION How can I execute the integration test using the dependency resolution of the main code?

5
  • 1
    Is Main.class in @SpringBootTest(classes = Main.class), your @SpringBootApplication class? Commented Aug 24, 2017 at 11:54
  • Yes, it is the @SpringBootApplication annotated class Commented Aug 24, 2017 at 12:27
  • 2
    @SpringBootTest and the @Data tests are mutually exclusive. Commented Aug 24, 2017 at 13:04
  • Didn't know that, but even removing @SpringBootTest, the problem is still the same Commented Aug 24, 2017 at 13:38
  • It worked! I removed the DataMongoTest and it seem it can resolve dependencies now. However, I was using the DataMongoTest to use an in-memory database instead of the real one. But that is another problem. Thanks @M.Deinum! Commented Aug 24, 2017 at 13:45

2 Answers 2

8

As @M.Deinum remarked in comments, @SpringBootTest and @DataMongoTest are mutually exclusive, so removing @DataMongoTest solved the problem.

However, if you still want to use the @DataMongoTest annotation, you can use this sentence:

@DataMongoTest(includeFilters = @ComponentScan.Filter(Service.class)) 

That way, all classes that are annotated with @Component will be loaded and autowired. This includes (among others) @Service, @Repository and @Controller.

Sign up to request clarification or add additional context in comments.

2 Comments

you mean: @DataMongoTest(includeFilters = @ComponentScan.Filter(Component.class))
But this way its also loading real database configuration, how to exclude that ?
1

I needed to add test for my storage service and I needed to autowire MongoRepository. The answer to this question did not solve my problem. However I found a solution and will share here in case someone else needs. I solved it as following:

Repository:

@Repository public interface MyRepository extends MongoRepository<MyEntity, String> { } 

Entity:

@Document(collection = "my_entity") public class MyEntity { @Id private String id; } 

Service:

@Service public class StorageServiceImpl implements StorageService { private final MyRepository repository; public StorageServiceImpl(MyRepository repository) { this.repository = repository; } ... } 

Test:

@Import(ObjectMapperConfiguration.class) @DataMongoTest class StorageServiceImplTest { @Autowired private MyRepository repository; private StorageService storageService; @BeforeEach void setup() { storageService = new StorageServiceImpl(repository); var entity = new MyEntity(); repository.save(entity); } @Test void create() { assertEquals(1, repository.count()); var entity = storageService.create(); assertEquals(2, repository.count()); } ... } 

Test Config:

@TestConfiguration public class ObjectMapperConfiguration { @Bean public ObjectMapper objectMapper() { return new ObjectMapper(); } } 

Test Application

@SpringBootApplication public class TestApplication { } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.