【问题标题】:Mockito throws NotAMockException using spring mvc injectionMockito 使用 spring mvc 注入抛出 NotAMockException
【发布时间】:2015-04-21 15:15:39
【问题描述】:

大家好,

我正在尝试在使用 spring mvc 的 Web 应用程序上使用 mockito 进行测试。 当它执行这一行 "Mockito.reset(notificacaoRepositoryMock);" 它抛出 "org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class com.sun .proxy.$Proxy40"

我在示例中看到了它并且它有效,我在这里找不到我做错了什么。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestContext.class, WebAppConfig.class})
@WebAppConfiguration
public class NotificacaoControllerTest {

    private MockMvc mockMvc;

    @Autowired
    private NotificacaoRepository notificacaoRepositoryMock;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Before
    public void setUp() {
        // *** Error here ***
        Mockito.reset(notificacaoRepositoryMock);

        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

我的 TestContext 是:

@Configuration
public class TestContext {

       @Bean
        public MessageSource messageSource() {
            ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();

            messageSource.setBasename("i18n/messages");
            messageSource.setUseCodeAsDefaultMessage(true);

            return messageSource;
        }

        @Bean
        public NotificacaoRepository notificacaoRepository() {
            return Mockito.mock(NotificacaoRepository.class);
        }
}

我要模拟的类是 CrudRepository 接口

public interface NotificacaoRepository extends CrudRepository<Notificacao, Long> {
}

而且,我认为我的 pom.xml 的相关部分是(spring 版本和 mockito)

<properties>
    <hibernate.version>4.2.0.Final</hibernate.version>
    <mysql.connector.version>5.1.21</mysql.connector.version>
    <spring.version>4.1.6.RELEASE</spring.version>
    <spring.data.version>1.8.0.RELEASE</spring.data.version>
</properties>
...
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-jpa</artifactId>
      <version>${spring.data.version}</version>
  </dependency>

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>3.2.3.RELEASE</version>
    <scope>test</scope>
</dependency>

更新

@jfcorugedo 我完全按照您所说的进行了尝试,但我一直收到同样的错误。我的测试上下文只是

@Configuration
public class TestContext {
        @Bean
        @Primary
        public NotificacaoRepository notificacaoRepository() {
            return Mockito.mock(NotificacaoRepository.class);
        }
}

我现在的测试课是:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WebAppConfig.class})
@WebAppConfiguration
@Import({TestContext.class})
public class NotificacaoControllerTest {

    @Autowired
    NotificacaoRepository notificacaoRepositoryMock;

    @Before
    public void setUp() {
        Mockito.reset(notificacaoRepositoryMock); // Error >> org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class com.sun.proxy.$Proxy55
        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

【问题讨论】:

  • 您是否尝试将@Mock NotificacaoRepository repo; 放在测试类的开头而不是创建一个bean?
  • @mtyurt:这行不通,因为他使用的是@RunWith(SpringJUnit4ClassRunner.class) 测试运行器,而不是@RunWith(MockitoJUnitRunner.class) 运行器。
  • 在更高版本的 mockito 中有一个 MockitoRule 允许这样做

标签: java spring spring-mvc mockito


【解决方案1】:

这是因为 Spring 在你的 bean 周围创建了一个代理。

尽量不要使用 Spring 注入 mock

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestContext.class, WebAppConfig.class})
@WebAppConfiguration
public class NotificacaoControllerTest {

    private MockMvc mockMvc;

    private NotificacaoRepository notificacaoRepositoryMock;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Before
    public void setUp() {
        notificacaoRepositoryMock = Mockito.mock(NotificacaoRepository.class);
        Mockito.reset(notificacaoRepositoryMock);

        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

【讨论】:

  • 此解决方案仅在测试类内部创建一个模拟,但它不会替换 Spring 实际使用的实例
  • 是的,要管理依赖注入,可以查看:lkrnac.net/blog/2014/01/mock-autowired-fields
  • 我建议看看 Springockito。
【解决方案2】:

据我所知,您正试图用模拟版本替换 spring bean。

在这种情况下,您必须使用注释 @Primary 来注释生成模拟的方法,因此 Spring 可以在每个自动装配字段中默认选择模拟对象(当然,如果它没有任何限定符)。

如果您尝试在测试中使用包含一些 real bean 和其他 mock bean 的 Spring 上下文,则必须按照以下步骤操作:

  • 在您的测试文件夹中创建一个 @Configuration 类,用于注入您要模拟的 bean 的模拟实例
  • 在您的测试中导入此配置类

例如:

注入模拟的配置类

import static org.mockito.Mockito.mock;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import xxx.xxx.xxx.NotificacaoRepository;

@Configuration
public class MockConfigurer {

    @Bean
    @Primary
    public NotificacaoRepository registerMock() {
        return mock(NotificacaoRepository.class);
    }
}

测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WebAppConfig.class})
@WebAppConfiguration
@Import({MockConfigurer.class})
public class NotificacaoControllerTest {

    //Now the instance injected here should be a mock object
    @Autowired
    private NotificacaoRepository notificacaoRepositoryMock;

    ...
}

【讨论】:

  • Vyncent 的解决方案奏效了,无论如何,我尝试在 TestContext.class 的 bean 方法中使用@Primary,但我一直收到同样的错误。我没有更改任何内容,我只是添加了@Primary 注释
  • 不,我不这么认为。使用 Vyncent 的解决方案,您只是创建了一个模拟 NotificacaoRepository,但您在哪里使用它? Spring 有它的 自己的实例 这个 bean,所以你唯一要做的就是在你的测试中创建一个模拟
  • @Vyncent 此链接显示如何模拟自动装配字段,但在这种情况下,测试具有正在测试的对象。它测试 OrderService 并创建一个 OrderService 对象来调用测试的方法。在我的情况下,我没有对象,我使用带有 MockMvc mockMvc.perform(post("/notificacao") 的 POST 进行测试
猜你喜欢
  • 2015-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-16
  • 2023-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多