JdbcTemplate Mockito ClassCastException - spring

I am trying to mock a method of the Spring framework's JdbcTemplate class. The method has the following signature:
public <T> T queryForObject(String sql, Class<T> requiredType) throws DataAccessException {...}
The mocking is being done as mentioned below:
when(jdbcTemplate.queryForObject(anyString(), eq(String.class))).thenReturn("data");
However, this call throws the following exception
java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$ce187d66 cannot be cast to java.lang.String
at test.DaoJdbcTest.setUp(DaoJdbcTest.java:81)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
Any idea as to what I am doing wrong?
Thanks in advance~
EDIT:
Here's the full code:
public class DaoJdbc extends NamedParameterJdbcSupport {
public String query(String sql) {
return getJdbcTemplate().queryForObject(sql, String.class);
}
}
public class DaoJdbcTest {
#Mock(answer = Answers.RETURNS_SMART_NULLS)
private JdbcTemplate jdbcTemplate;
private DaoJdbc dao;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
dao = new DaoJdbc();
dao.setJdbcTemplate(jdbcTemplate);
Mockito.when(jdbcTemplate.queryForObject(anyString(), Matchers.eq(String.class))).thenReturn("data");
}
#Test
public void testQuery() {
String ret = dao.query("select 'test' from dual");
assertEquals("data", ret);
verify(jdbcTemplate).queryForObject(anyString(), eq(String.class));
}
}

Remove the answer = Answers.RETURNS_SMART_NULLS. Test passes when I remove that. What does that feature do? The default null behavior works fine for me.
As a bonus, you can also use the MockitoJunitRunner to clean up the code a bit...
#RunWith(MockitoJUnitRunner.class)
public class DaoJdbcTest {
#Mock
private JdbcTemplate jdbcTemplate;
#InjectMocks
private DaoJdbc dao;
#Before
public void setUp() throws Exception {
Mockito.when(jdbcTemplate.queryForObject(anyString(), Matchers.eq(String.class))).thenReturn("data");
}
#Test
public void testQuery() {
String ret = dao.query("select 'test' from dual");
assertEquals("data", ret);
verify(jdbcTemplate).queryForObject(anyString(), eq(String.class));
}
}

Related

Spring Boot Test model attribute does not exist

Im trying to test a controller, Author Controller, which returns a view with a model. The problem is on the testInitUpdateAuthor() test where its not able to find the model or attribute name specifically. All other methods are fine with their model/attribute tests.
Any advice?
#Slf4j
#Controller
public class AuthorController {
private final AuthorService authorService;
private final String CREATEORUPDATEFORM = "author/createOrUpdateAuthor";
public AuthorController(AuthorService authorService) {
this.authorService = authorService;
}
#GetMapping("/author/{id}/update")
public String updateAuthor(#PathVariable("id") Long id, Model model) {
model.addAttribute("author", authorService.findById(id));
return CREATEORUPDATEFORM;
}
#ExtendWith(MockitoExtension.class)
#SpringBootTest
class AuthorControllerTest {
MockMvc mockMvc;
#Mock
AuthorService authorService;
#InjectMocks
AuthorController authorController;
#BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(authorController).build();
}
#Test
void getIndex() throws Exception {
mockMvc.perform(get("/author/index"))
.andExpect(status().isOk())
.andExpect(view().name("author/index"))
.andExpect(model().attributeExists("authors"));
}
#Test
void testInitUpdateAuthor() throws Exception {
when(authorService.findById(anyLong())).thenReturn(Author.builder().id(1L).build());
mockMvc.perform(get("/author/1/update"))
.andExpect(status().isOk())
.andExpect(view().name("author/createOrUpdateAuthor"))
.andExpect(model().attributeExists("author"));
}
}

No primary or default constructor found for Pageable in Pact Contract Provider test

I set up following pact contract provider test
#RunWith(SpringRestPactRunner.class)
#Provider("structures")
#PactFolder("pacts")
#VerificationReports({"console", "markdown"})
#SpringBootTest
public class ContractTest {
#MockBean
private MyServiceImpl myServiceImpl;
#Autowired
private MyController myController;
#Configuration
public static class TestConfiguration {
#Bean
public MyController myController() {
return new MyController();
}
}
#TestTarget
public final MockMvcTarget target = new MockMvcTarget();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
target.setControllers(myController);
}
#State("My state")
public void setupDocumentWithStructures() {
Mockito.when(myService.getStructuresByDocumentId(
ArgumentMatchers.eq("1"),
ArgumentMatchers.any()
)).thenReturn(new PageImpl<>(Arrays.asList(
Structure.of("first"),
Structure.of("second")
)));
}
}
Running the test results in:
java.lang.AssertionError:
0 - Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.data.domain.Pageable
java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.data.domain.Pageable
The method getStructuresByDocumentId expects a Pageable object as its second argument. Changing the annotation #SpringBootTest to
#WebMvcTest(MyController.class)
#EnableSpringDataWebSupport
Doesn't solve the problem. Any ideas, how to solve this issue?
you used "myService" in your setupDocumentWithStructures whereas your #MockBean is myServiceImpl.......I think you meant to use myServiceImpl in setupDocumentWithStructures
That's how it can work
#Before
public void setupOrInit() {
this.mockMvc = MockMvcBuilders.standaloneSetup(controller)
.setControllerAdvice(new ErrorRequestInterceptor(tracer))
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();
}
I was having the same problem and fixed setting a new mockMvc like this
#Before
public void before() {
MockitoAnnotations.initMocks(this);
target.setMockMvc(MockMvcBuilders.standaloneSetup(myController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build());
}
I am not using #SpringBootTest as you are, but I think in this case it does not matter. Below is my entire (redacted) code.
#RunWith(SpringRestPactRunner.class)
#Provider("my-provider")
#PactBroker(url = "https://pact-broker.my-compnay.com")
public class MyControllerProviderContractTest {
#TestTarget
public final MockMvcTarget target = new MockMvcTarget();
#Mock
private MyService myService;
#InjectMocks
private MyController myController = new MyController();
#Before
public void before() {
MockitoAnnotations.initMocks(this);
target.setMockMvc(MockMvcBuilders.standaloneSetup(myController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build());
}
#State("my state")
public void stateForMyMethod() {
//my mocks
}
}
I hope this helps, I spend a few hours trying to solve this.
Cheers

Null Pointer Exception while calling a RestController using Mockmvc perform() method in SpringBoot

I am using MockMvc for the first type. What I am doing is testing a Restcontroller in SPringboot.
I have a Restcontroller like this,
#RequestMapping("/address")
public class AddressController {
#RequestMapping("/createAddress")
public Address craeteAddress(Address address)
{
Address add=addressService.createAdd(address);
return add;
}
#RequestMapping("/getAll")
public List<Address> getAll()
{
return addressService.getAll();
}
}
Now my test class looks like this,
public class AddressControllerTest {
AddressService addressService = mock(AddressService.class);
#Autowired
MockMvc mockMvc;
private static final String ADDRESS_DTO_JSON =
"{" +
"\"id\":\"123\"," +
"\"pacsId\":\"345\"," +
"}";
List<Object> object = new ArrayList<Object>();
#Before
public void setup() {
}
#Test
public void createAddressTest() throws Exception {
//System.out.println("The Json Content :" + ADDRESS_DTO_JSON);
this.mockMvc
.perform(get("address/getAll"))
.andExpect(status().isOk())
.andReturn();
}
}
I am trying to call the 'address/getAll' method in the restcontroller. When i run the junit method it says 'Null Pointer Exception' near the .perform(get("address/getAll")) line.
I did some research but did not work out. Can someone please help ?
I think you misconfigured your test class.
Try something like this:
#RunWith(SpringRunner.class)
#WebMvcTest(AddressController.class)
public class AddressControllerTest {
#Autowired
MockMvc mockMvc;
}

Not able to mock jdbcTemplate in Spring boot Test class

I am using Spring boot and Mockito for testing. I have been able to write test cases for Service layer and they re working fine. But, the test cases for DAO layer do not. The jdbcTemplate object that is mocked and autowired gives null pointer when executing the test case. Below are the details:
My DAOTest class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = EcommerceApplication.class)
public classEcommerceDaoTest {
#InjectMocks
private IEcommerceDao ecommerceDao = new EcommerceDaoImpl();
#Mock
#Autowired
private JdbcTemplate as400JdbcTemplate;
#Before
public void setUp() throws Exception
{
MockitoAnnotations.initMocks(this);
}
#Test
public void checkOrderExistsTest() throws EcommerceException{
Mockito.when(as400JdbcTemplate.queryForObject(queryForOrder,new Object[]
{"1000"}, int.class)).thenReturn(1);
boolean exists =
ecommerceDao.checkOrderExists("1000");
assertTrue(exists);
}
}
EcommerceDAOImpl.java:
#Override
public boolean checkOrderExists(String orderNo)throws EcommerceException{
boolean doesExist = false;
int count = 0;
try{
count= as400JdbcTemplate.queryForObject(queryForOrder, new Object[]{orderNo}, int.class);
if(count >0){
doesExist = true;
}
}
catch(Exception e){
}
return doesExist;
}
AS400Config.java:
#Bean
#Autowired
public JdbcTemplate as400JdbcTemplate(#Qualifier("as400DataSource")DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
ECommerceApplication.java
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class })
#EnableTransactionManagement
#Import(As400Configuration.class)
public class EcommerceApplication {
public static void main(String[] args) {
SpringApplication.run(EcommerceApplication.class, args);
}
}
When I am running the test case, I am getting NullPointerException for as400JdbcTemplate. The functionality works fine as is. Its just the test cases for DAO layer that fail because of the inability of the jdbcTemplate to get mocked/autowired.
Please let me know where I am going wrong.
You don't need to use #Mock and #Autowired at the same time. Use only #Mock:
#Mock
private JdbcTemplate as400JdbcTemplate;
Use instead of #RunWith(SpringRunner.class) --> #RunWith(MockitoJUnitRunner.class)
Also to inject mock into DAO you can use ReflectionTestUtils from spring test.
public static void setField(Class targetClass, String name, Object value)
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(ecommerceDao ,"as400JdbcTemplate" ,
as400JdbcTemplate);
}
#Mock
private JdbcTemplate as400JdbcTemplate;

How to inject a bean in a ConstraintValidator with MockMVC?

I have a custom ConstraintValidator:
#Component
public class FooValidator implements ConstraintValidator<FooAnnotation, String> {
#Inject
private FooRepository fooRepository;
#Override
public void initialize(FooAnnotation foo) {
}
#Override
public boolean isValid(String code, ConstraintValidatorContext context) {
Foo foo = fooRepository.findByCode(code);
//My code
}
}
In my Junit tests and MockMVC I call the url but fooRepository bean validator is always null.
How I can inject it in my test controller? I tried to create a mock repository but it is also null.
My source code test:
public class FooControllerTest {
#InjectMocks
private FooController fooController;
private MockMvc mockMvc;
#Before
public void setup() {
// Process mock annotations
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(fooController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();
}
#Test
public void testSave() throws Exception {
Foo foo = new Foo();
// given
//My code...
// when
// then
// with errors
this.mockMvc.perform(post("/foo/update")
.param("name", "asdfasd")
.sessionAttr("foo", foo))
.andExpect(model().hasErrors())
.andExpect(model().attributeHasFieldErrors("foo", "name"));
}
}
You should add a #ContextConfiguration to your test, among other things.

Resources