JCN
JCN

Reputation: 539

MockBean annotation in Spring Boot test causes NoUniqueBeanDefinitionException

I am having trouble using the @MockBean annotation. The docs say MockBean can replace a bean within the context, but I am getting a NoUniqueBeanDefinitionException within my unit test. I can't see how to use the annotation. If I can mock the repo, then obviously there will be more than one bean definition.

I am following the examples found here: https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4

I have a mongo repository:

public interface MyMongoRepository extends MongoRepository<MyDTO, String>
{
   MyDTO findById(String id);
}

And a Jersey resource:

@Component
@Path("/createMatch")
public class Create
{
    @Context
    UriInfo uriInfo;

    @Autowired
    private MyMongoRepository repository;

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Response createMatch(@Context HttpServletResponse response)
    {
        MyDTO match = new MyDTO();
        match = repository.save(match);
        URI matchUri = uriInfo.getBaseUriBuilder().path(String.format("/%s/details", match.getId())).build();

        return Response.created(matchUri)
                .entity(new MyResponseEntity(Response.Status.CREATED, match, "Match created: " + matchUri))
                .build();
    }
}

And a JUnit test:

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestMocks {

    @Autowired
    private TestRestTemplate restTemplate;

    @MockBean
    private MyMongoRepository mockRepo;

    @Before
    public void setup()
    {
        MockitoAnnotations.initMocks(this);

        given(this.mockRepo.findById("1234")).willReturn(
                new MyDTO());
    }

    @Test
    public void test()
    {
        this.restTemplate.getForEntity("/1234/details", MyResponseEntity.class);

    }

}

Error message:

Field repository in path.to.my.resources.Create required a single bean, but 2 were found:
    - myMongoRepository: defined in null
    - path.to.my.MyMongoRepository#0: defined by method 'createMock' in null

Upvotes: 12

Views: 31183

Answers (3)

Łukasz Olszewski
Łukasz Olszewski

Reputation: 915

I had the same "issue" in spring-boot 2.3.9 but it's not a bug, it's problem with the configuration of beans.

At least, There are two ways to solve it:

Set name parameter in @MockBean annotation:

In the test, add a name to MockBean:

@MockBean(name="myRepository")
private MyRepository diffrentName;

and in the production codebase use myRepository as filed name :

@Autowired
private MyRepository myRepository;

The name of @MockBean must be the same as the name of the field.

Name a MockBean filed the same as a dependency in code.

In the test, use the correct name of MockBean filed:

@MockBean
private MyRepository customRepository;

and in the production codebase use customRepository as filed name :

@Autowired
private MyRepository customRepository;

in that way, You indicate which bean You want to use.

I hope this will be helpful for someone.

Upvotes: 2

Snehal Masne
Snehal Masne

Reputation: 3429

Just add below in POM.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Upvotes: 0

alexbt
alexbt

Reputation: 17065

It's a bug: https://github.com/spring-projects/spring-boot/issues/6541

The fix is in spring-data 1.0.2-SNAPSHOT and 2.0.3-SNAPSHOT : https://github.com/arangodb/spring-data/issues/14#issuecomment-374141173

If you aren't using these version, you can work around it by declaring the mock with its name:

@MockBean(name="myMongoRepository")
private MyMongoRepository repository;

In response to your comment

From Spring's doc:

For convenience, tests that need to make REST calls to the started server can additionally @Autowire a TestRestTemplate which will resolve relative links to the running server.

Reading this, I think you need to declare @SpringBootTest with a web environment:

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

If your spring boot doesn't start the web environment, then what is the need for TestRestTemplate. Thus, I guess spring does not even make it available.

Upvotes: 15

Related Questions