Spring Contract does not reach method #Before on base class - junit4

I have a single spring contract test:
public class ContractVerifierTest extends BaseClassForIntegrationTests {
#Test
public void validate_shouldSayHello() throws Exception {
// given:
RequestSpecification request = given()
.header("Content-Type", "application/json");
// when:
Response response = given().spec(request)
.get("/sayhello/Eduardo");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field("['msg']").isEqualTo("hello Eduardo");
}
}
My base class looks like:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = DemoApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT)
#Slf4j
public class BaseClassForIntegrationTests {
#Value("${app.url}") private String url;
#Value("${app.port}") private int port;
#Before
public void setup() {
log.error("Running setup with url:" + url + ":" + port);
RestAssured.baseURI = url;
RestAssured.port = port;
}
}
The setup method is never reached, funny thing, if I change the annotation to #BeforeEach or #BeforeAll it works as expected.
I have a sample of the project here

With Contract 3.0.x the default testing framework is junit5 you need to Configure the plugin explicitly to use junit 4

Related

Junit , Mockito Integration with Vertx

I am new vertx wanted to know which is the best junit framework and references that we should went through.
I tried using couple of things with mockito but services are not getting injected.
Please help in this.
UPDATE:
My TestClass looks something like this
public class GroupModeTest {
private static final Logger logger = LoggerFactory.getLogger(GroupMode.class);
public static GroupModeService service;
public static GroupModeDao dao;
private GroupMode groupMode;
private static GroupModeDao daoMock;
#BeforeAll
static void setup() {
logger.info("Starting Unit Tests for GroupMode");
daoMock = mock(GroupModeDao.class);
dao = new GroupModeDao();
service = new GroupModeService(daoMock);
}
#BeforeEach
void init() {
logger.info("Mocking new GroupMode Entity");
this.groupMode = new GroupMode();
}
#Test
public void testFakeWithMockito() throws IOException {
IGroupModeDao iGroupModeDao = mock(IGroupModeDao.class);
GroupMode groupMode = new GroupMode();
groupMode.setId(1L);
groupMode.setModeType("unique");
groupMode.setCreatedBy(1);
groupMode.setCreatedOn(LocalDateTime.now());
groupMode.setUpdatedBy(1);
groupMode.setUpdatedOn(LocalDateTime.now());
Single<Long> expected=Single.just(1L);
when(iGroupModeDao.create(groupMode)).thenReturn(expected);
GroupModeService groupModeService = new GroupModeService(iGroupModeDao);
Single<Long> actual= groupModeService.rxCreate("unique",1);
assertEquals(expected, actual);
}
}

Error while testing: found multiple declaration of #BootstrapWith for test class

I would like to test my CRUD REST Controller for the first time. I have watched some videos and come up with this idea but I am getting error. I am using JPA with mySql. ITodoService is simple interface with CRUD methods. My rest Controller is working when I test it via Postman, so code there is ok.
If you could give me some feedback what might be wrong and where can I check for good imformation about testing REST app because I have spent like 3 hrs without any success :)
#SpringBootTest
#RunWith(SpringRunner.class)
#WebMvcTest
public class TodoFinalApplicationTests {
#Autowired
private MockMvc mockMvc;
#MockBean
private ITodosService iTodosService;
#Test
public void getAllTodosTest() throws Exception {
Mockito.when(iTodosService.findAll()).thenReturn(
Collections.emptyList()
);
MvcResult mvcResult = mockMvc.perform(
MockMvcRequestBuilders.get("/todos")
.accept(MediaType.APPLICATION_JSON)
).andReturn();
System.out.println(mvcResult.getResponse());
Mockito.verify(iTodosService.findAll());
}
}
Error message:
java.lang.IllegalStateException: Configuration error: found multiple declarations of #BootstrapWith for test class [com.damian.todo_Final.TodoFinalApplicationTests]: [#org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.context.SpringBootTestContextBootstrapper), #org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTestContextBootstrapper)]
EDIT:
This is code for whole CRUD REST Test
#RunWith(SpringRunner.class)
#AutoConfigureMockMvc
#SpringBootTest(classes = TodoFinalApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
// #WebMvcTest
public class TodoFinalApplicationTests {
#Autowired
private TestRestTemplate restTemplate;
#LocalServerPort
private int port;
private String getRootUrl() {
return "http://localhost:" + port;
}
#Test
public void contextLoads() {
}
#Test
public void getAllTodos() {
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity<String> response = restTemplate.exchange(getRootUrl() + "/employees",
HttpMethod.GET, entity, String.class);
assertNotNull(response.getBody());
}
#Test
public void createNewTodo() {
Todos todo = new Todos();
todo.setId(5);
todo.setTaskDate("15.01.1990");
todo.setTaskStatus(true);
todo.setTaskDescritpion("Description for testing");
ResponseEntity<Todos> postResponse = restTemplate.postForEntity(getRootUrl() + "/todos", todo, Todos.class);
assertNotNull(postResponse);
assertNotNull(postResponse.getBody());
}
#Test
public void testUpdateTodo() {
int id = 1;
Todos todo = restTemplate.getForObject(getRootUrl() + "/todos/" + id, Todos.class);
todo.setTaskDate("15.01.1990");
todo.setTaskStatus(true);
todo.setTaskDescritpion("Updating");
restTemplate.put(getRootUrl() + "/todos/" + id, todo);
Todos updatedTodo = restTemplate.getForObject(getRootUrl() + "/todos/" + id, Todos.class);
assertNotNull(updatedTodo);
}
#Test
public void testDeletedTodo() {
int id = 3;
Todos todo = restTemplate.getForObject(getRootUrl() + "/todos/" + id, Todos.class);
assertNotNull(todo);
restTemplate.delete(getRootUrl() + "/todos/" + id);
try {
todo = restTemplate.getForObject(getRootUrl() + "/todos/" + id, Todos.class);
} catch (final HttpClientErrorException e) {
assertEquals(e.getStatusCode(), HttpStatus.NOT_FOUND);
}
}
You have both #SpringBootTest and #WebMvcTest on one test class. Both classes, among others, specify only what beans should be instantiated in the test context.
The definitions are conflicting, so only one is allowed.
Decide if you want to test:
entire application context - use #SpringBootTest
only controllers - use #WebMvcTest
In your case, I would:
remove #SpringBootTest
specify Controller you want to test in #WebMvcTest
Alternatively, you can
remove #WebMvTest
add AutoConfigureWebMvc
#SpringBootTest brings all beans into context, and thus #WebMvcTest will likely result in a faster test.

Integration Tests for RESTEasy Endpoint

I want to perform integration tests on my REST endpoint but am running into issues.
Below is my endpoint. NOTE: I cannot change this part of the code.
#Path("/people")
public class PersonResource {
private final PersonService personService;
#Inject
public PersonResource(final PersonService personService) {
this.personService = personService;
}
#GET
#Produces("application/json")
public List<Person> getPersonList() {
return personService.getPersonList();
}
}
From what I've been able to find online, I have the following basic structure for my test.
public class PersonResourceTest {
private Dispatcher dispatcher;
private POJOResourceFactory factory;
#Before
public void setup() {
dispatcher = MockDispatcherFactory.createDispatcher();
factory = new POJOResourceFactory(PersonResource.class);
dispatcher.getRegistry().addResourceFactory(factory);
}
#Test
public void testEndpoint() throws URISyntaxException {
MockHttpRequest request = MockHttpRequest.get("people");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
System.out.print("\n\n\n\n\n" + response.getStatus() + "\n\n\n\n\n");
System.out.print("\n\n\n\n\n" + response.getContentAsString() + "\n\n\n\n\n");
}
}
However, this results in the following error on the last line of the setup method.
java.lang.RuntimeException: RESTEASY003190: Could not find constructor for class: my.path.PersonResource
I explored the Registry API and thought maybe I should have been using addSingletonResource instead, so I changed the last line of setup to dispatcher.getRegistry().addSingletonResource(personResource); and added the following.
#Inject
private PersonResource personResource;
But that results in a NullPointerException on the last line of setup.
The sparse documentation on the mocking isn't very helpful. Can anyone point out where I'm going wrong? Thanks.
You need to do two things
Add a no arguments constructor to your source class:
public PersonResource() {
this(null)
}
In the test class, initialize the PersonResource class with an instance of PersonService class:
dispatcher.getRegistry().addSingletonResource(new PersonResource(new PersonService()));
If needed, the PersonService class can be mocked:
private Dispatcher dispatcher;
#Mock
private PersonService service;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
dispatcher = MockDispatcherFactory.createDispatcher();
PersonResource resource= new PersonResource(service);
ispatcher.getRegistry().addSingletonResource(resource);
}
Hope it helps!

How can I change the feign URL during the runtime?

#FeignClient(name = "test", url="http://xxxx")
How can I change the feign URL (url="http://xxxx") during the runtime? because the URL can only be determined at run time.
You can add an unannotated URI parameter (that can potentially be determined at runtime) and that will be the base path that will be used for the request. E.g.:
#FeignClient(name = "dummy-name", url = "https://this-is-a-placeholder.com")
public interface MyClient {
#PostMapping(path = "/create")
UserDto createUser(URI baseUrl, #RequestBody UserDto userDto);
}
And then the usage will be:
#Autowired
private MyClient myClient;
...
URI determinedBasePathUri = URI.create("https://my-determined-host.com");
myClient.createUser(determinedBasePathUri, userDto);
This will send a POST request to https://my-determined-host.com/create (source).
Feign has a way to provide the dynamic URLs and endpoints at runtime.
The following steps have to be followed:
In the FeignClient interface we have to remove the URL parameter. We have to use #RequestLine annotation to mention the REST method (GET, PUT, POST, etc.):
#FeignClient(name="customerProfileAdapter")
public interface CustomerProfileAdaptor {
// #RequestMapping(method=RequestMethod.GET, value="/get_all")
#RequestLine("GET")
public List<Customer> getAllCustomers(URI baseUri);
// #RequestMapping(method=RequestMethod.POST, value="/add")
#RequestLine("POST")
public ResponseEntity<CustomerProfileResponse> addCustomer(URI baseUri, Customer customer);
#RequestLine("DELETE")
public ResponseEntity<CustomerProfileResponse> deleteCustomer(URI baseUri, String mobile);
}
In RestController you have to import FeignClientConfiguration
You have to write one RestController constructor with encoder and decoder as parameters.
You need to build the FeignClient with the encoder, decoder.
While calling the FeignClient methods, provide the URI (BaserUrl + endpoint) along with rest call parameters if any.
#RestController
#Import(FeignClientsConfiguration.class)
public class FeignDemoController {
CustomerProfileAdaptor customerProfileAdaptor;
#Autowired
public FeignDemoController(Decoder decoder, Encoder encoder) {
customerProfileAdaptor = Feign.builder().encoder(encoder).decoder(decoder)
.target(Target.EmptyTarget.create(CustomerProfileAdaptor.class));
}
#RequestMapping(value = "/get_all", method = RequestMethod.GET)
public List<Customer> getAllCustomers() throws URISyntaxException {
return customerProfileAdaptor
.getAllCustomers(new URI("http://localhost:8090/customer-profile/get_all"));
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public ResponseEntity<CustomerProfileResponse> addCustomer(#RequestBody Customer customer)
throws URISyntaxException {
return customerProfileAdaptor
.addCustomer(new URI("http://localhost:8090/customer-profile/add"), customer);
}
#RequestMapping(value = "/delete", method = RequestMethod.POST)
public ResponseEntity<CustomerProfileResponse> deleteCustomer(#RequestBody String mobile)
throws URISyntaxException {
return customerProfileAdaptor
.deleteCustomer(new URI("http://localhost:8090/customer-profile/delete"), mobile);
}
}
I don`t know if you use spring depend on multiple profile.
for example: like(dev,beta,prod and so on)
if your depend on different yml or properties. you can define FeignClientlike:(#FeignClient(url = "${feign.client.url.TestUrl}", configuration = FeignConf.class))
then
define
feign:
client:
url:
TestUrl: http://dev:dev
in your application-dev.yml
define
feign:
client:
url:
TestUrl: http://beta:beta
in your application-beta.yml (I prefer yml).
......
thanks god.enjoy.
use feign.Target.EmptyTarget
#Bean
public BotRemoteClient botRemoteClient(){
return Feign.builder().target(Target.EmptyTarget.create(BotRemoteClient.class));
}
public interface BotRemoteClient {
#RequestLine("POST /message")
#Headers("Content-Type: application/json")
BotMessageRs sendMessage(URI url, BotMessageRq message);
}
botRemoteClient.sendMessage(new URI("http://google.com"), rq)
You can create the client manually:
#Import(FeignClientsConfiguration.class)
class FooController {
private FooClient fooClient;
private FooClient adminClient;
#Autowired
public FooController(ResponseEntityDecoder decoder, SpringEncoder encoder, Client client) {
this.fooClient = Feign.builder().client(client)
.encoder(encoder)
.decoder(decoder)
.requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))
.target(FooClient.class, "http://PROD-SVC");
this.adminClient = Feign.builder().client(client)
.encoder(encoder)
.decoder(decoder)
.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
.target(FooClient.class, "http://PROD-SVC");
}
}
From documentation: https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html#_creating_feign_clients_manually
In interface you can change url by Spring annotations. The base URI is configured in yml Spring configuration.
#FeignClient(
name = "some.client",
url = "${some.serviceUrl:}",
configuration = FeignClientConfiguration.class
)
public interface SomeClient {
#GetMapping("/metadata/search")
String search(#RequestBody SearchCriteria criteria);
#GetMapping("/files/{id}")
StreamingResponseBody downloadFileById(#PathVariable("id") UUID id);
}
Use #PathVariable like this:
#Service
#FeignClient(name = "otherservicename", decode404 = true)
public interface myService {
#RequestMapping(method = RequestMethod.POST, value = "/basepath/{request-path}")
ResponseEntity<String> getResult(#RequestHeader("Authorization") String token,
#RequestBody HashMap<String, String> reqBody,
#PathVariable(value = "request-path") String requestPath);
}
Then from service, construct the dynamic url path and send the request:
String requestPath = "approve-req";
ResponseEntity<String> responseEntity = myService.getResult(
token, reqBody, requestPath);
Your request url will be at: "/basepath/approve-req"
I prefer to build feign client by configuration to pass a url at run time (in my case i get the url by service name from consul discovery service)
so i extend feign target class as below:
public class DynamicTarget<T> implements Target<T> {
private final CustomLoadBalancer loadBalancer;
private final String serviceId;
private final Class<T> type;
public DynamicTarget(String serviceId, Class<T> type, CustomLoadBalancer loadBalancer) {
this.loadBalancer = loadBalancer;
this.serviceId = serviceId;
this.type = type;
}
#Override
public Class<T> type() {
return type;
}
#Override
public String name() {
return serviceId;
}
#Override
public String url() {
return loadBalancer.getServiceUrl(name());
}
#Override
public Request apply(RequestTemplate requestTemplate) {
requestTemplate.target(url());
return requestTemplate.request();
}
}
var target = new DynamicTarget<>(Services.service_id, ExamsAdapter.class, loadBalancer);
package commxx;
import java.net.URI;
import java.net.URISyntaxException;
import feign.Client;
import feign.Feign;
import feign.RequestLine;
import feign.Retryer;
import feign.Target;
import feign.codec.Encoder;
import feign.codec.Encoder.Default;
import feign.codec.StringDecoder;
public class FeignTest {
public interface someItfs {
#RequestLine("GET")
String getx(URI baseUri);
}
public static void main(String[] args) throws URISyntaxException {
String url = "http://www.baidu.com/s?wd=ddd"; //ok..
someItfs someItfs1 = Feign.builder()
// .logger(new FeignInfoLogger()) // 自定义日志类,继承 feign.Logger
// .logLevel(Logger.Level.BASIC)// 日志级别
// Default(long period, long maxPeriod, int maxAttempts)
.client(new Client.Default(null, null))// 默认 http
.retryer(new Retryer.Default(5000, 5000, 1))// 5s超时,仅1次重试
// .encoder(Encoder)
// .decoder(new StringDecoder())
.target(Target.EmptyTarget.create(someItfs.class));
// String url = "http://localhost:9104/";
//
System.out.println(someItfs1.getx(new URI(url)));
}
}

Spring restful service test case fail HTTP status is 500

I want to implement test case for spring restful web services which return a json
MY controller test class is :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {WebAppContext.class,JpaTestConfiguration.class
})
#WebAppConfiguration
public class DominProfileRestControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void testGetDomainProfile() throws Exception {
String profileId = domainProfile.getId().toString();
System.out.print("testing restful"+profileId);
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.city", is("Chandigrah")));
/* mockMvc.perform(get("/service/domainprofile/get/{id}",profileId).accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().contentType("text/plain;charset=ISO-8859-1"))
.andExpect(content().string("hello Prashant"));
*/
}
My Controller class Is :
#RestController
#RequestMapping("/service/domainprofile")
public class DominProfileRestController {
#Autowired
private JpaDomainProfileRepository jpaDomainProfileRepository;
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public DomainProfileResource getDomainProfile(#PathVariable String id) {
JpaDomainProfile domainProfile = jpaDomainProfileRepository.findOne(Long.valueOf(id));
DomainProfileResource domainProfileResource = new DomainProfileResource();
System.out.println("domainProfile.getCity()*************" + domainProfile.getCity());
System.out.println("domainProfile.getAddress()*************" + domainProfile.getAddress());
domainProfileResource.setCity(domainProfile.getCity());
domainProfileResource.setAddress(domainProfile.getAddress());
// return new ResponseEntity<DomainProfileResource>(domainProfileResource, HttpStatus.OK);
return domainProfileResource;
// return domainProfile;
}
}
When I run test case I got An error while we got values in domainprofile.city and domainprofile.address.
Error Is :
java.lang.AssertionError: Status
Expected :200
Actual :500
It Is Working Fine When I return a plain text
can you do this
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andDo(print());
this will print the full response with exception , now if you see HttpMessageNotWritableException which was the issue I was facing , you should try to serialize your object using jackson and see if it works (spring internally uses Jackson ). For example , If any of your fields are null the Serialization will fail.