【问题标题】:MockBean annotation in Spring Boot test causes NoUniqueBeanDefinitionExceptionSpring Boot 测试中的 MockBean 注解导致 NoUniqueBeanDefinitionException
【发布时间】:2017-01-18 18:55:21
【问题描述】:

我在使用 @MockBean 注释时遇到问题。文档说 MockBean 可以替换上下文中的 bean,但我在单元测试中得到了 NoUniqueBeanDefinitionException。我看不到如何使用注释。如果我可以模拟 repo,那么显然会有不止一个 b​​ean 定义。

我正在关注此处找到的示例:https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4

我有一个 mongo 存储库:

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

还有泽西岛资源:

@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();
    }
}

还有一个 JUnit 测试:

@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);

    }

}

错误信息:

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

【问题讨论】:

    标签: java mongodb spring-boot spring-data mockito


    【解决方案1】:

    我在spring-boot 2.3.9 中遇到了同样的“问题”,但这不是错误,而是 bean 的配置问题。

    至少,有两种方法可以解决:

    在@MockBean注解中设置name参数:

    在测试中,给MockBean添加一个name

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

    在生产代码库中使用 myRepository 作为文件名:

    @Autowired
    private MyRepository myRepository;
    

    @MockBean 的名称必须与字段的名称相同。

    将 MockBean 文件命名为与代码中的依赖项相同。

    在测试中,使用正确的 MockBean 文件名:

    @MockBean
    private MyRepository customRepository;
    

    在生产代码库中使用customRepository 作为文件名:

    @Autowired
    private MyRepository customRepository;
    

    通过这种方式,您指明要使用哪个 bean。

    我希望这对某人有所帮助。

    【讨论】:

    • 谢谢,这很有帮助!但是,如果我在 prod 和 test 中具有相同的名称,并且名称与类型相同,则它不起作用。因此,如果我在 prod 代码库和测试中都有 XyzRepository xyzRepository,它就会抱怨。
    【解决方案2】:

    只需在 POM.xml 中添加以下内容

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

    【讨论】:

      【解决方案3】:

      这是一个错误:https://github.com/spring-projects/spring-boot/issues/6541

      修复在 spring-data 1.0.2-SNAPSHOT2.0.3-SNAPSHOT 中:https://github.com/arangodb/spring-data/issues/14#issuecomment-374141173

      如果您不使用这些版本,您可以通过使用其名称声明模拟来解决它:

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

      回应您的评论

      来自Spring's doc

      为方便起见,需要对开始的 REST 调用的测试 服务器还可以 @Autowire 一个 TestRestTemplate 这将 解析到正在运行的服务器的相对链接。

      读到这里,我觉得你需要用网络环境声明@SpringBootTest

      @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
      

      如果你的spring boot没有启动web环境,那还需要TestRestTemplate。因此,我猜 spring 甚至没有提供它。

      【讨论】:

      • 谢谢。我试过了,现在 Spring 无法自动装配 TestRestTemplate:org.springframework.beans.factory.UnsatisfiedDependencyException:创建名称为“path.to.my.tests.TestMocks”的 bean 时出错:通过字段“restTemplate”表示不满足的依赖关系:没有限定为依赖项 [org.springframework.boot.test.web.client.TestRestTemplate] 找到类型为 [org.springframework.boot.test.web.client.TestRestTemplate] 的 bean:预计至少有 1 个 bean 有资格作为此依赖项的自动装配候选者.
      • 啊,是的,我已经删除了 webenvironment 的东西并忘记了。我重新添加了它,现在我收到一个关于我的 DTO 类没有合适的 HttpMessageConverter 的错误。所以看起来我已经摆脱了最初的错误,开始学习 HttpMessageConverters。谢谢!
      • 您使用的是哪个 spring-boot 版本?
      猜你喜欢
      • 2015-09-12
      • 1970-01-01
      • 2019-08-10
      • 2017-03-21
      • 2022-01-04
      • 1970-01-01
      • 2023-01-19
      • 1970-01-01
      • 2018-07-27
      相关资源
      最近更新 更多