Problem
Running mvn test
returns the following error in the unit test of a Mongo repository:
Error creating bean with name 'my_package.infrastructure.mongo.repositories.UserRepositoryMongoImplTests': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'my_package.infrastructure.mongo.repositories.users.UserRepositoryMongoImpl' available
As you can see in the code below I made sure to add the @Repository
annotation to my implementation class (AKA UserRepositoryMongoImpl
), I also tried with the @Component
annotation, but it did not work. Then I tried to add the @ComponentScan("my_package")
annotation to my configuration class but still without success.
Code
I am using Java 11
, Spring Boot
, JUnit
and TestContainers
. My folder structure is as follow:
.
├── src/
│ ├── main/
│ │ └── java/
│ │ └── my_package/
│ │ ├── domain/
│ │ │ └── users/
│ │ │ ├── User.java
│ │ │ └── UserRepository.java
│ │ ├── infrastructure/
│ │ │ └── mongo/
│ │ │ └── repositories/
│ │ │ └── UserRepositoryMongoImpl.java
│ │ └── ApplicationConfig.java
│ └── test/
│ └── my_package/
│ └── infrastructure/
│ └── mongo/
│ └── repositories/
│ └── UserRepositoryMongoImplTests.java
└── pom.xml
UserRepository.java
public interface UserRepository {
public User findByUsername(String username);
public User save(User user);
public void delete(User user);
}
ApplicationConfig.java
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("my_package")
public class ApplicationConfig {
}
UserRepositoryMongoImpl.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
import my_package.domain.users.User;
import my_package.domain.users.UserRepository;
@Repository
public class UserRepositoryMongoImpl implements UserRepository {
@Autowired
private MongoTemplate mongoTemplate;
private static final String COLLECTION_NAME = "users";
@Override
public User findByUsername(String username) {
return mongoTemplate.findOne(Query.query(Criteria.where("username").is(username)), User.class, COLLECTION_NAME);
}
@Override
public User save(User user) {
return mongoTemplate.save(user, COLLECTION_NAME);
}
@Override
public void delete(User user) {
mongoTemplate.remove(user, COLLECTION_NAME);
}
}
UserRepositoryMongoImplTests.java
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import my_package.domain.users.User;
import my_package.infrastructure.mongo.repositories.users.UserRepositoryMongoImpl;
@Testcontainers
@DataMongoTest(excludeAutoConfiguration = {
EmbeddedDataSourceConfiguration.class
})
public class UserRepositoryMongoImplTests {
@Autowired
private UserRepositoryMongoImpl userRepository;
@Container
private MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.4.4"));
@BeforeEach
void mongoDbContainerStarting() {
mongoDBContainer.start();
System.setProperty("spring.data.mongodb.uri", mongoDBContainer.getReplicaSetUrl());
}
@AfterEach
void mongoDbContainerStoping() {
mongoDBContainer.stop();
}
@Test
public void shouldSaveValidNewUser() {
User user = new User("username123", "heuehueheuh");
user = userRepository.save(user);
assert(user.id() != null);
assert(user.username().equals("username123"));
assert(user.password().equals("heuehueheuh"));
}
}
And for last: pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>br.nom.carneiro.carlos</groupId>
<artifactId>future_software_003-ws</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>my-project</name>
<description>Random description</description>
<properties>
<java.version>11</java.version>
<testcontainers.version>1.15.2</testcontainers.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mongodb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-guava</artifactId>
<version>3.4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.8</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<doctype>book</doctype>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-asciidoctor</artifactId>
<version>${spring-restdocs.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Questions I looked up before
- Unsatisfied dependency expressed through field 'clientRepository';
- UnsatisfiedDependencyException: Error creating bean with name
- Unsatisfied dependency expressed through field 'userRepository'
If you can offer me advice, any input will be appreciated.
Edit
I tried to create the Bean manually adding the following code to my configuration class:
@Bean
public UserRepositoryMongoImpl userRepositoryMongoImpl() {
return new UserRepositoryMongoImpl();
}
Then I got the following error:
The bean 'userRepositoryMongoImpl', defined in class path resource [blablabla], could not be registered. A bean with that name has already been defined in file [blablabla] and overriding is disabled.
This probably means that the bean is being correctly declared through the @Repository
annotation, but for some reason Spring is not finding it to inject in my test class.