JCN JCN - 2 months ago 131
Java Question

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

Answer

It seems like a bug: https://github.com/spring-projects/spring-boot/issues/6541

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 makes it available. I'm not able to test it now, please let me know.