Mockito throws NotAMockException using spring mvc injection
Guy wang,
I am trying to execute a test using mockito in a web application using spring mvc. When it executes this line "Mockito.reset (notificacaoRepositoryMock);" it throws "org.mockito.exceptions.misusing.NotAMockException: The argument must be mock, but this is: class com.sun.proxy. $ Proxy40"
I saw that in the example and it worked, I cannot find what I am doing wrong here.
@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();
}
My 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);
}
}
The class I want to mock is the CrudRepository interface
public interface NotificacaoRepository extends CrudRepository<Notificacao, Long> {
}
and I think the relevant part of my pom.xml is (spring versions and 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>
UPDATE
@jfcorugedo i tried exactly what you said but i keep getting the same error. My test context is just
@Configuration
public class TestContext {
@Bean
@Primary
public NotificacaoRepository notificacaoRepository() {
return Mockito.mock(NotificacaoRepository.class);
}
}
and my test 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();
}
source to share
This is because Spring creates a proxy around your bean.
Try not injecting layout with Spring
@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();
}
source to share
As far as I know, you are trying to replace the spring bean with a mock version.
In this case, you have to annotate the method that produces your annotated layout @Primary
, so spring can choose the default object layout in each auto-substitution field (unless it has any determinant, of course).
If you are trying to use spring context in your test, which has real beans and different beans layout, you should follow these steps:
- Create a class
@Configuration
in the test folder where you inject the mock instance beans you want to mock - Import this config class into your test
For example:
The configuration class that injects the layout
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);
}
}
Test 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;
...
}
source to share