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

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

Related

Spring Boot Unit Testing MockMvc Null Body

I am having dificulties with using MockMvc.
Here I have simple Service and controller classes:
Service:
#Slf4j
#Service
public class EmployeeService {
//...
public Employee GetSample() {
//...
//filling Employee Entities
return new Employee(
"Harriet"
, "random"
, 25);
}
}
controller:
#RestController
#RequestMapping(value = "/info")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
#Validated
public class EmployeeController {
private final EmployeeService employeeService;
#PostMapping("/GetEmployee")
public ResponseEntity<Employee> GetEmployee() {
Employee employee = employeeService.GetSample();
return new ResponseEntity<>(employee, HttpStatus.OK);
}
}
Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EmployeeTestCase {
private MockMvc mockMvc;
#InjectMocks
private EmployeeController EmployeeController;
#Mock
private EmployeeService employeeService;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(employeeController).build();
}
#Test
public void getEmployee() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/info/GetEmployee")).andDo(print());
}
}
when I try to use MockMvc I get null body. It seems employee is null. But I didn't understand why.
I thought that when test uses perform, it should initialise employee and later on it should't be null.
I tried to cut the code as much as possible. I hope it is not long.
Note : also tried to use Mockito.when(employeeController.GetEmployee()).thenCallRealMethod();
The #SpringBootTest annotation loads the complete Spring application
context. That means you do not mock your layers
(Services/Controllers).
If you wanted to test specific layers of your application, you could look into test slice annotations offered by Springboot: https://docs.spring.io/spring-boot/docs/current/reference/html/test-auto-configuration.html
In contrast, a test slice annotation only loads beans required to test a particular layer. And because of this, we can avoid unnecessary mocking and side effects.
An example of a Test Slice is #WebMvcTest
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = HelloController.class,
excludeFilters = {
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}
)
public class HelloControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void hello() throws Exception {
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
#Test
public void helloDto() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(
get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.amount", is(amount)));
}
}
However if you really wanted to load up the SpringBoot Application context, say for an Integration Test, then you have a few options:
#SpringBootTest
#AutoConfigureMockMvc
public class TestingWebApplicationTest {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class AuctionControllerIntTest {
#Autowired
AuctionController controller;
#Autowired
ObjectMapper mapper;
MockMvc mockMvc;
#Before
public void setUp() throws Exception {
System.out.println("setup()...");
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void create_ValidAuction_ShouldAddNewAuction() throws Exception {
final Auction auction = new Auction(
"Standing Desk",
"Stand up desk to help you stretch your legs during the day.",
"Johnnie34",
350.00);
mockMvc.perform(post("/auctions")
.contentType(MediaType.APPLICATION_JSON)
.content(toJson(auction)))
.andExpect(status().isCreated());
}
}
Lets say you don't want to load up any layers at all, and you want to mock everything, such as for example a Unit Test:
#RunWith(MockitoJUnitRunner.class)
class DemoApplicationTest {
#Mock
private UserRepository userRepository;
private Demo noneAutoWiredDemoInstance;
#Test
public void testConstructorCreation() {
MockitoAnnotations.initMocks(this);
Mockito.when(userRepository.count()).thenReturn(0L);
noneAutoWiredDemoInstance = new Demo(userRepository);
Assertions.assertEquals("Count: 0", noneAutoWiredDemoInstance.toString());
}
}

Spring - How to test Controller with ApplicationEventPublisher dependency?

I have a Controller which is publishing an event
#RestController
public class Controller
{
#Autowired
private ApplicationEventPublisher publisher;
#GetMapping("/event")
public void get()
{
publisher.publishEvent(new Event());
}
}
Now I want to test that the event is published. First I tried to #MockBean the ApplicationEventPublisher and verify the method call. But this does not work according to https://jira.spring.io/browse/SPR-14335
So I am doing it like this:
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = Controller.class)
public class ControllerTest
{
#Autowired
private MockMvc mockMvc;
#Test
public void getTest() throws Exception
{
this.mockMvc.perform(get("/").contentType(MediaType.APPLICATION_JSON)
.andExpect(status().isOk());
assertNotNull(Listener.event);
}
#TestConfiguration
static class Listener
{
public static Event event;
#EventListener
void listen ( Event incoming )
{
event = incoming;
}
}
}
Is there an easier way for this common use case?
You can do it like this
#RunWith(SpringRunner.class)
public class ControllerTest {
private MockMvc mockMvc;
#MockBean
private ApplicationEventPublisher publisher;
#Before
public void setup() {
Controller someController= new Controller(publisher);
mockMvc = MockMvcBuilders.standaloneSetup(someController).build();
}
#Test
public void getTest() throws Exception
{
ArgumentCaptor<Event> argumentCaptor = ArgumentCaptor.forClass(Event.class);
doAnswer(invocation -> {
Event value = argumentCaptor.getValue();
//assert if event is correct
return null;
}).when(publisher).publishEvent(argumentCaptor.capture());
this.mockMvc.perform(get("/").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(publisher, times(1)).publishEvent(any(Event.class));
}
}
And also change Field Injection to Constructor Injection in your controller class(It is a good practice).
#RestController
public class Controller
{
private ApplicationEventPublisher publisher;
#Autowired
public Controller(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
....
}
im facing the same problem, and for now i solve the problem using TestConfiguration:
#SpringBootTest
class MyUseCaseIT {
#Autowired private ApplicationEventPublisher publisher;
#Autowired private MyService service;
#Test
void callUseCase() {
var event = mock(MyEvent.class);
doNothing().when(publisher).publishEvent(event);
service.useCase();
verify(publisher).publishEvent(event);
}
#TestConfiguration
static class MockitoPublisherConfiguration {
#Bean
#Primary
ApplicationEventPublisher publisher() {
return mock(ApplicationEventPublisher.class);
}
}
Another possiblity would be that you replace the ApplicationEventPublisher instance on your controller with the mock instance using reflection in your test:
public class ControllerTest {
...
// Collect your controller
#Autowired
private Controller controller;
// Use the mock publisher
#MockBean
private ApplicationEventPublisher publisherMock;
// E.g. in setup set the mock publisher on your controller
#Before
public void setup() {
ReflectionTestUtils.setField(controller, "publisher", publisherMock);
}
...

Method when() from Mockito do not work correctly

I have problem with mockito method: when(...). When I test:
afterThrowExceptionShouldReturnCorrectHttpStatus()
Ran first, then the second test:
controllerShouldReturnListOfAnns()
It always fails because it throw NotFoundException. When I delete the first test or running second test as first, then everything is correct. This look like method when() from first test override method when() form the second test There is test code and test configuration.
#ActiveProfiles("dev")
#RunWith(SpringRunner.class)
#SpringBootTest
public class AnnTestController {
#Autowired
private AnnounService annSrv;
#Autowired
private AnnounRepo annRepo;
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void contextLoads() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Test
public void afterThrowExceptionShouldReturnCorrectHttpStatus() throws Exception {
when(this.annRepo.getAnnounList()).thenThrow(NotFoundAnnounException.class);
this.mockMvc.perform(get("/ann/list")).andExpect(status().isNotFound());
}
#Test
public void controllerShouldReturnListOfAnns() throws Exception {
List<Announcement> lst = new ArrayList<>();
lst.add(new Announcement(1, "test", "test"));
when(annRepo.getAnnounList()).thenReturn(lst);
this.mockMvc.perform(get("/ann/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].id", is(1)));
}}
Config:
#Profile("dev")
#Configuration
public class BeanConfig {
#Bean
public CommentsRepo commentsRepo() {
return mock(CommentsRepo.class);
}}
You can try somthing like that:
#After public void reset_mocks() {
Mockito.reset(this.annRepo);
}

Mocking the Qualified beans using mockito for a spring-boot application

consider my scenario
public class SomeClass {
#Autowired #Qualifier("converter1") private IConverter converter1;
#Autowired #Qualifier("converter2") private IConverter converter2;
public void doSomeAction(String mimeType) {
converter1.execute();
converter2.execute();
}
}
This is my code.
In order to test this
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#Mock(name="converter1") IConverter converter1;
#Mock(name="converter2") IConverter converter2;
#InjectMocks SomeClass class = new SomeClass();
#Test
public void testGetListOfExcelConverters() throws Exception {
class.doSomeAction("abcd");
}
}
Here the mocks are not getting injected, please help with the proper mechanism for mocking a qualified beans.
If this is not the right way to code using spring, please let me know the correct method for using this.
Not sure what error you are getting, but your test class doesn't compile because you have what looks like you intend to be a variable name using the keyword class. This worked for me:
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#Mock(name="converter1") IConverter converter1;
#Mock(name="converter2") IConverter converter2;
#InjectMocks
SomeClass clazz = new SomeClass();
#Test
public void testGetListOfExcelConverters() throws Exception {
clazz.doSomeAction("abcd");
verify(converter1).execute();
verify(converter2).execute();
}
}
And by "worked for me" I mean that the test actually ran and passed. Note I added a couple of verify statements to assert that the injected mocks got called.
I used the SomeClass code you provided as-is.
For me, both existing answers were insufficient.
#riddy 's answer did not take into account different test cases.
#jhericks ' answer did not use the Spring context, which caused other issues down the line.
Here's my solution:
#MockBean
#Qualifier("myNamedBean")
private SomeBean someBean;
As simple as that.
You can mock beans using a test configuration:
#Configuration
public class TestConfig {
#Bean
public MyService myService() {
return Mockito.mock( MyService.class );
}
}
I've found this solution:
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#Mock()
#Qualifier("converter1")
IConverter converter1;
#Mock()
#Qualifier("converter1")
IConverter converter2;
#InjectMocks SomeClassTest testObj = new SomeClassTest();
#Test
public void testGetListOfExcelConverters() throws Exception {
testObj.doSomeAction("abcd");
verify(converter1).execute();
verify(converter2).execute();
}
}
BTW, I haven't found this in doc.
In my app, the #Autowired beans are passed as constructor args. None of the variations (albeit JUnit 5 version) were working. Instead, I had to "kick it old school" and simply instantiate the mocks directly.
public class SomeClass {
private final IConverter converter1;
private final IConverter converter2;
public SomemClass( #Autowired #Qualifier("converter1") conv1,
#Autowired #Qualifier("converter2") conv2 ) {
this.converter1 = conv1;
this.converter2 = conv2;
}
public void doSomeAction(String mimeType) {
converter1.execute();
converter2.execute();
}
}
public class SomeClassTest {
IConverter converter1;
IConverter converter2;
SomeClass pojo;
#BeforeEach
public void setup() {
converter1 = Mockito.mock( IConverter.class );
converter2 = Mockito.mock( IConverter.class );
pojo = new SomeClass( converter1, converter2 );
}
#Test
public void testGetListOfExcelConverters() throws Exception {
pojo.doSomeAction("abcd");
}
}

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