I have this test class - currently it is checking the response at the endpoint
Endpoints.SEDA_PROCESS_ENDPOINT
but I need it to check at
"mock:"+Endpoints.SEDA_PROCESS_ENDPOINT
Is there a way to forward the response to this mock endpoint I have just defined?
below is my test class
package com.sams.pricing.prism.data.processor;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import org.apache.camel.EndpointInject;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.spring.MockEndpoints;
import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.sams.pricing.prism.data.processor.model.CostIQRetail;
import com.sams.pricing.prism.data.processor.routes.PrismRouter;
import com.sams.pricing.prism.data.processor.service.RulesEngineClient;
import com.sams.pricing.prism.data.processor.util.Endpoints;
#SpringBootTest
#CamelSpringBootTest
#MockEndpoints( Endpoints.SEDA_PROCESS_ENDPOINT)
public class CamelRouteTests3 {
#Autowired
private ProducerTemplate template;
#EndpointInject( "mock:" + Endpoints.SEDA_PROCESS_ENDPOINT)
private MockEndpoint mock;
#Mock
private PrismRouter p;
#Mock
private RulesEngineClient rulesEngineClientMock;
public CostIQRetail costIQObject() {
CostIQRetail obj = new CostIQRetail();
obj.setItemNbr(123);
obj.setLocationNbr(4931);
obj.setIsDcFlag(false) ;
obj.setStatus("SUCCESS");
obj.setOrderableCost(new BigDecimal((10.0)));
obj.setWarehousePackCost(new BigDecimal(100.0));
obj.setOrderablePrepaidCost(null) ;
obj.setOrderableCollectCost(null) ;
obj.setReasonCode("Markdown - category funded");
obj.setEffectiveDate("2022-12-29");
obj.setIsFutureEffectiveDate(false);
obj.setCostType("WAREHOUSE PACK COST");
obj.setSource("COST IQ");
obj.setCreatedBy("lab1 account");
obj.setCreatedByUserId("LB-cost-test");
obj.setCreatedTs("2022-12-29T02:42:25.529Z");
obj.setCurrentRetailPrice(new BigDecimal(55.0)) ;
obj.setCurrentOrderableCost(null);
obj.setCurrentWarehousePackCost(new BigDecimal((0.0)));
obj.setCurrentOrderablePrepaidCost(null) ;
obj.setCurrentOrderableCollectCost(null);
obj.setMarginChange(new BigDecimal((-100.0)));
obj.setOwedToClub(new BigDecimal((0.0)));
obj.setItemSourceId(3572924);
obj.setPriceDestId(701800);
obj.setCategory(87);
obj.setOrderableQty(null);
obj.setOldMargin(new BigDecimal((100.0)));
obj.setNewMargin(new BigDecimal(0.0));
return obj;
}
private String costIQPayloadString() throws JsonProcessingException
{
String key = "{\"retailTypeReasonCode\":{\"retailTypeReasonCodeId\":{\"retailType\":\"BP\",\"retailReasonCode\":\"CC\"}},\"expirationDate\":null,\"customerRetailAmount\":0.0,\"auditMessage\":null,\"createdTimestamp\":null,\"clientID\":\"COST IQ\",\"rowNumber\":0,\"auditRecordTimestamp\":null,\"clubNumber\":4931,\"itemNumber\":123,\"effectiveDate\":\"2022-12-29\",\"submissionID\":null,\"retailAmount\":55.0,\"createdBy\":\"lab1 account\"}";
String key2 = "{\"retailTypeReasonCode\":{\"retailTypeReasonCodeId\":{\"retailType\":\"BP\",\"retailReasonCode\":\"CC\"}},\"expirationDate\":null,\"customerRetailAmount\":0.0,\"auditMessage\":null,\"createdTimestamp\":null,\"clientID\":\"COST IQ\",\"rowNumber\":0,\"auditRecordTimestamp\":null,\"categoryId\":87,\"subCategoryId\":1,\"clubNumber\":4931,\"itemNumber\":123,\"effectiveDate\":\"2022-12-29\",\"submissionID\":null,\"retailAmount\":10.0,\"createdBy\":\"lab1 account\"}";
return key2;
}
#Test
void test() throws Exception {
// Set up the mock endpoints
mock.expectedBodiesReceived(costIQPayloadString());
//p.interceptSendToEndpoint( Endpoints.SEDA_PROCESS_ENDPOINT).to(mock.getEndpointUri());
Mockito.when(rulesEngineClientMock.validateRules((costIQObject()))).thenReturn(costIQObject()); //.thenR
Map<String, Object> headers = new HashMap<>();
headers.put("appName", "costIQ");
// Send the test message to the SEDA_SEND_ENDPOINT
template.sendBodyAndHeaders(Endpoints.SEDA_SEND_ENDPOINT, costIQObject(), headers);
mock.assertIsSatisfied();
}
}
I have looked at advice with but that involves adding in the cameltestsupport and would need to re-write this code. Is there a way to do this with current implementations?
Related
I have this problem where Mockito returns the result the actual controller would have given if the service has started. I want it to return the goats list I made and set in the when() function.
package com.goatpool.goatpool;
import com.goatpool.goatpool.controller.GoatController;
import com.goatpool.goatpool.model.Goat;
import com.goatpool.goatpool.service.HBMGoatService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
#RunWith(MockitoJUnitRunner.class)
class GoatControllerTest {
#InjectMocks
GoatController goatController;
#Mock
HBMGoatService hbmgoatService;
#Before
public void setup(){
//runs before the tests
}
#Test
void testGetAllGoats() throws Exception {
//Arrange
List<Goat> goats = new ArrayList<>();
goats.add(new Goat(1, "1","20001","buck", new Date() ,12.02f,1,3,24.68f,null,"Some Info",true,100));
goats.add(new Goat(2,"2","20056","doe",new Date() ,16.02f,1,3,20.68f,null ,"Some Info",true,12));
goats.add(new Goat(3,"3","21060","doe",new Date() ,16.02f,1,3,0f,null,"No Info",true,12));
goats.add(new Goat(4,"4","1212","buck",new Date() ,1.3f,1,3,0.5f,null,"No Info",true,12));
//Act
MockitoAnnotations.initMocks(this);
Mockito.when(hbmgoatService.getGoatList()).thenReturn(goats); //mock
List<Goat> result = goatController.getAllGoats();
//Assert
String actualResults = result.toString();
String expectedResults = goats.toString();
Assert.assertEquals(expectedResults, actualResults);
}
}
In my handler function I have this method
public Mono<ServerResponse> itemsEx(ServerRequest serverRequest) {
throw new RuntimeException("RuntimeException Occured");
}
Now, I want to handle this exception, so I override AbstractErrorWebExceptionHandler and create this class.
package com.learnreactivespring.learnreactivespring.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Mono;
import java.util.Map;
#Component
#Slf4j
public class FunctionalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
public FunctionalErrorWebExceptionHandler(ErrorAttributes errorAttributes,
ApplicationContext applicationContext,
ServerCodecConfigurer serverCodecConfigurer) {
super(errorAttributes, new ResourceProperties(), applicationContext);
super.setMessageWriters(serverCodecConfigurer.getWriters());
super.setMessageReaders(serverCodecConfigurer.getReaders());
}
#Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
private Mono<ServerResponse> renderErrorResponse(ServerRequest serverRequest) {
ErrorAttributeOptions errorAttributes = ErrorAttributeOptions.of(ErrorAttributeOptions.Include.MESSAGE);
Map<String, Object> errorAttributesMap = getErrorAttributes(serverRequest, errorAttributes);
log.info("errorAttributesMap : " + errorAttributesMap);
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(errorAttributesMap.get("message")));
}
The problem is, that I have still a Stacktrace in my terminal... but I explicitly defined ErrorAttributeOptions only with message.
My current version of Spring Boot is 2.3.1.RELEASE. In previous version (2.1.1) I didn't have this problem because I used to this
package com.learnreactivespring.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Mono;
import java.util.Map;
#Component
#Slf4j
public class FunctionalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
public FunctionalErrorWebExceptionHandler(ErrorAttributes errorAttributes,
ApplicationContext applicationContext,
ServerCodecConfigurer serverCodecConfigurer) {
super(errorAttributes, new ResourceProperties(), applicationContext);
super.setMessageWriters(serverCodecConfigurer.getWriters());
super.setMessageReaders(serverCodecConfigurer.getReaders());
}
#Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
private Mono<ServerResponse> renderErrorResponse(ServerRequest serverRequest) {
Map<String, Object> errorAttributesMap = getErrorAttributes(serverRequest, false);
log.info("errorAttributesMap : " + errorAttributesMap);
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(errorAttributesMap.get("message")));
}
}
Now, after bumped version of Spring Boot this issue occured.
You should use ErrorAttributeOptions.defaults(). But note that by default message is always empty (and stacktrace is not present).
So you probably want to use something like this:
ErrorAttributeOptions options = ErrorAttributeOptions
.defaults()
.including(ErrorAttributeOptions.Include.MESSAGE)
;
And use .excluding(.) if you want to exclude something.
I am trying to take a test driven development approach to building a Java based app running on App Engine, but I am having difficulties getting the setup working.
My servlet
package mobi.grocerymonkey.groceryapp;
import com.google.appengine.api.utils.SystemProperty;
import java.io.IOException;
import java.io.BufferedReader;
import java.util.Properties;
import org.json.JSONObject;
import java.util.logging.Logger;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import static com.googlecode.objectify.ObjectifyService.ofy;
import com.googlecode.objectify.ObjectifyService;
/* This is the servlet */
#WebServlet(name = "GroceryServlet", value = "/grocery")
public class GroceryServlet extends HttpServlet {
private static final Logger log = Logger.getLogger(GroceryServlet.class.getName());
#Override
public void init() throws ServletException {
log.info("context init");
ObjectifyService.init();
ObjectifyService.register(Grocery.class);
}
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.setContentType("text/plain");
response.getWriter().println("Hello Kitty");
}
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
BufferedReader reader = request.getReader();
String line = null;
StringBuffer stringBuffer = new StringBuffer();
while((line = reader.readLine()) != null) {
stringBuffer.append(line);
}
String jsonString = stringBuffer.toString();
JSONObject json = new JSONObject(jsonString);
log.info("JSON "+ jsonString);
Grocery grocery = new Grocery();
grocery.setName((String) json.get("name"));
grocery.setQuantity((Integer) json.get("quantity"));
ofy().save().entity(grocery).now();
log.info("JSON name "+ grocery.getName());
response.setContentType("application/json");
response.getWriter().println(jsonString);
}
}
web.xml file
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
</web-app>
My unit test
package mobi.grocerymonkey.groceryapp;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.DatastoreOptions;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.json.JSONObject;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.Reader;
import java.io.Closeable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Unit tests for {#link HelloAppEngine}.
*/
#RunWith(JUnit4.class)
public class GroceryServletTest {
private static final String MOCK_URL = "/grocery";
// Set up a helper so that the ApiProxy returns a valid environment for local testing.
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
private Closeable closeable;
#Mock
private HttpServletRequest mockRequest;
#Mock
private HttpServletResponse mockResponse;
private StringWriter responseWriter;
private GroceryServlet servletUnderTest;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
helper.setUp();
ObjectifyService.init(new ObjectifyFactory(
DatastoreOptions.newBuilder()
.setHost("http://localhost:8081")
.setProjectId("enduring-trees-259812")
.build()
.getService()
));
closeable = ObjectifyService.begin();
// Set up some fake HTTP requests
when(mockRequest.getRequestURI()).thenReturn(MOCK_URL);
JSONObject grocery = new JSONObject();
grocery.put("name", "Beer");
Reader inputString = new StringReader(grocery.toString());
BufferedReader reader = new BufferedReader(inputString);
when(mockRequest.getReader()).thenReturn(reader);
// Set up a fake HTTP response.
responseWriter = new StringWriter();
when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter));
servletUnderTest = new GroceryServlet();
servletUnderTest.init();
}
#After public void tearDown() throws Exception {
closeable.close();
helper.tearDown();
}
#Test
public void doGetWritesResponse() throws Exception {
servletUnderTest.doGet(mockRequest, mockResponse);
// We expect our hello world response.
assertThat(responseWriter.toString())
.contains("Hello Kitty");
}
#Test
public void doPostWritesResponse() throws Exception {
JSONObject reqObj = new JSONObject();
reqObj.put("name", "Beer");
reqObj.put("quantity", 5);
StringReader reader = new StringReader(reqObj.toString());
when(mockRequest.getReader()).thenReturn(new BufferedReader(new StringReader(reqObj.toString())));
servletUnderTest.doPost(mockRequest, mockResponse);
// We expect our hello world response.
assertThat(responseWriter.toString())
.contains(reqObj.getString("name"));
}
}
The test fails with the following error message
[ERROR] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time
elapsed: 0.103 s <<< FAILURE! - in
mobi.grocerymonkey.groceryapp.GroceryServletTest [ERROR]
doPostWritesResponse(mobi.grocerymonkey.groceryapp.GroceryServletTest)
Time elapsed: 0.078 s <<< ERROR! java.lang.IllegalStateException: You
have not started an Objectify context. You are probably missing the
ObjectifyFilter. If you are not running in the context of an http
request, see the ObjectifyService.run() method. at
mobi.grocerymonkey.groceryapp.GroceryServletTest.doPostWritesResponse(GroceryServletTest.java:109)
which is caused by this line ofy().save().entity(grocery).now() in my servlet. When I remove it, the test is run without errors.
I have tried to follow different approaches to resolve this error found here on stackoverflow but without luck.
How should the test/app be setup to be able to develop it using a test driven approach? What I am looking for is a way to be able to write the unit test first and then the actual application. But how to succeed?
(Disclaimer, I haven't worked with Java in over a decade)
UPDATE
ServletContext file
package mobi.grocerymonkey.groceryapp;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.Closeable;
import java.io.IOException;
import com.googlecode.objectify.ObjectifyService;
import static com.googlecode.objectify.ObjectifyService.ofy;
#WebListener
public class GroceryContextListener implements ServletContextListener {
private ServletContext context;
private Closeable closeable;
public void contextInitialized(ServletContextEvent event) {
this.context = event.getServletContext();
ObjectifyService.init();
this.closeable = ObjectifyService.begin();
ObjectifyService.register(Grocery.class);
System.out.println("Context initialized");
}
public void contextDestroyed(ServletContextEvent event) {
try {
this.closeable.close();
} catch(IOException ioe) {
}
}
}
Unittest file
package mobi.grocerymonkey.groceryapp;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.DatastoreOptions;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.json.JSONObject;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.Reader;
import java.io.Closeable;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
/**
* Unit tests for {#link HelloAppEngine}.
*/
#RunWith(JUnit4.class)
public class GroceryServletTest {
private static final String MOCK_URL = "/grocery";
// Set up a helper so that the ApiProxy returns a valid environment for local testing.
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
private Closeable closeable;
#Mock
private HttpServletRequest mockRequest;
#Mock
private HttpServletResponse mockResponse;
private ServletContextListener contextListener;
private ServletContext context;
private StringWriter responseWriter;
private GroceryServlet servletUnderTest;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
helper.setUp();
contextListener = new GroceryContextListener();
context = mock(ServletContext.class);
// Set up some fake HTTP requests
when(mockRequest.getRequestURI()).thenReturn(MOCK_URL);
JSONObject grocery = new JSONObject();
grocery.put("name", "Beer");
Reader inputString = new StringReader(grocery.toString());
BufferedReader reader = new BufferedReader(inputString);
when(mockRequest.getReader()).thenReturn(reader);
// when(mockRequest.getServletContext()).thenReturn(context);
// Set up a fake HTTP response.
responseWriter = new StringWriter();
when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter));
servletUnderTest = new GroceryServlet();
}
#After
public void tearDown() throws Exception {
helper.tearDown();
}
#Test
public void doGetWritesResponse() throws Exception {
servletUnderTest.doGet(mockRequest, mockResponse);
// We expect our hello world response.
assertThat(responseWriter.toString())
.contains("Hello Kitty");
}
#Test
public void doPostWritesResponse() throws Exception {
contextListener.contextInitialized(new ServletContextEvent(context));
JSONObject reqObj = new JSONObject();
reqObj.put("name", "Beer");
reqObj.put("quantity", 5);
StringReader reader = new StringReader(reqObj.toString());
when(mockRequest.getReader()).thenReturn(new BufferedReader(new StringReader(reqObj.toString())));
servletUnderTest.doPost(mockRequest, mockResponse);
// We expect our hello world response.
assertThat(responseWriter.toString())
.contains(reqObj.getString("name"));
}
}
Servlet file
package mobi.grocerymonkey.groceryapp;
import com.google.appengine.api.utils.SystemProperty;
import java.io.IOException;
import java.io.BufferedReader;
import java.util.Properties;
import org.json.JSONObject;
import java.util.logging.Logger;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import static com.googlecode.objectify.ObjectifyService.ofy;
import com.googlecode.objectify.ObjectifyService;
/* This is the servlet */
#WebServlet(name = "GroceryServlet", value = "/grocery")
public class GroceryServlet extends HttpServlet {
private static final Logger log = Logger.getLogger(GroceryServlet.class.getName());
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.setContentType("text/plain");
response.getWriter().println("Hello Kitty");
}
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
BufferedReader reader = request.getReader();
String line = null;
StringBuffer stringBuffer = new StringBuffer();
while((line = reader.readLine()) != null) {
stringBuffer.append(line);
}
String jsonString = stringBuffer.toString();
JSONObject json = new JSONObject(jsonString);
log.info("JSON "+ jsonString);
Grocery grocery = new Grocery();
grocery.setName((String) json.get("name"));
grocery.setQuantity((Integer) json.get("quantity"));
ofy().save().entity(grocery).now();
log.info("JSON name "+ grocery.getName());
response.setContentType("application/json");
response.getWriter().println(jsonString);
}
}
Now I am getting a "com.google.cloud.datastore.DatastoreException: Unauthenticated" error when running the test, so looks like I am on the right way. Would I store the datastore credentials in the web.xml and then pass them to the context similar to
ObjectifyService.init(new ObjectifyFactory(
DatastoreOptions.newBuilder()
.setHost("http://localhost:8081")
.setProjectId("enduring-trees-259812")
.build()
.getService()
));
ObjectifyService.factory().register(Grocery.class);
New Update
I upgraded to Junit5 and rewrote the entire test to this
package mobi.grocerymonkey.groceryapp;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.util.Closeable;
import static com.googlecode.objectify.ObjectifyService.factory;
import static com.googlecode.objectify.ObjectifyService.ofy;
import com.googlecode.objectify.Key;
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.testing.LocalDatastoreHelper;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import mobi.grocerymonkey.groceryapp.util.TestBase;
import mobi.grocerymonkey.groceryapp.domain.Grocery;
import mobi.grocerymonkey.groceryapp.domain.GroceryList;
public class MyFirstTest extends TestBase {
// Maximum eventual consistency.
private final static LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
Closeable closeable;
#BeforeAll
public static void setUp() {
helper.setUp();
}
#AfterAll
public static void tearDown() {
helper.tearDown();
}
#BeforeEach
public void setUpEach() {
ObjectifyService.init(new ObjectifyFactory(
DatastoreOptions.getDefaultInstance().getService()));
closeable = ObjectifyService.begin();
}
#AfterEach
public void tearDownEach() {
closeable.close();
}
#DisplayName("Test MyFirstTest.testAddition()")
#Test
public void testAddition() {
assertEquals(1 + 1, 2);
}
#DisplayName("Testing testGroceryList()")
#Test
public void testGroceryList() {
factory().register(GroceryList.class);
GroceryList list = new GroceryList("Weekend Beer List");
Key<GroceryList> k1 = ofy().save().entity(list).now();
assertEquals(1+1, 2);
}
}
It is deliberately kept in a single file for now. But for some reason, the datastore cannot find the emulator that is running when the test is run. I am getting a Datastore Unauthenticated error.
I ran gcloud beta emulators datastore start and $(gcloud beta emulators datastore env-init) before running the unit test.
The problem is that you're calling ObjectifyService.init() twice, but you only called begin() on the first (abandoned) factory.
You call init() in your setUp() method, which initializes the static ObjectifyFactory. You then open a session on that factory with the ObjectifyService.begin() call.
At the end of your setUp() you call servletUnderTest.init(), which also calls ObjectifyService.init(). This replaces the static ObjectifyFactory. When you next execute your servlet and call ofy()..., you're using a factory that has not started a session.
Take a look at the code for ObjectifyService. It's quite literally just a few lines of code to wrap a static ObjectifyFactory instance.
If you have more than one servlet, this code will not work well in production either - you only want to initialize and register your classes once. I recommend doing this with a ServletContextListener.
The core of test-driven development revolves around five steps, which you repeated throughout the software development life cycle.
Test-driven development life-cycle:
Write the test
Run the test (without implementation code, test does not pass)
Write just enough implementation so the test passes
Run all tests (test pass)
Refactor
Repeat
By following this steps you can create a TDD implementation for your application.
There is no specific way for Google Cloud to do beside the steps I have specified above.
As specified in your error, you can see that you have not started an Objectify context, and you are missing the ObjectifyFilter.
Here is a implementation of a list in Java, which follows the TDD, which may be helpful to clear some of your concerns.
I have a spring boot app with an Endpoint Test Configuration class and a unit test to test my http client. I am trying to get my server address and port from my application.properties which is located in my src/test.(All the classes are in my src/test.)
Here is my config class code :
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import javax.xml.bind.JAXBException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import com.nulogix.billing.service.PredictionEngineService;
import com.nulogix.billing.ws.endpoint.AnalyzeEndPoint;
import com.nulogix.billing.ws.endpoint.GetVersionEndPoint;
#Configuration
public class EndPointTestConfiguration {
#Value("${billing.engine.address}")
private String mockAddress;
#Value("${billing.engine.port}")
private String mockPort;
#Bean
public String getAddress() {
String serverAddress = "http://" + mockAddress + ":" + mockPort;
return serverAddress;
}
#Bean
public GetVersionEndPoint getVersionEndPoint() {
return new GetVersionEndPoint();
}
I annotated the values from my .properties with #value and then created a method that I instantiated with a bean to to return my server address string.
I then use that string value here in my HttpClientTest class:
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.Map;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ConfigurableApplicationContext;
import com.google.gson.Gson;
import com.nulogix.billing.configuration.EndPointTestConfiguration;
import com.nulogix.billing.mockserver.MockServerApp;
#SpringBootTest(classes = EndPointTestConfiguration.class)
public class HttpClientTest {
#Autowired
EndPointTestConfiguration endpoint;
public static final String request_bad = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|";
public static final String request_good = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|-123|-123|-123|0.0|0.0|0.0|0.0|0.0|0.0|0.0";
//gets application context
static ConfigurableApplicationContext context;
//call mock server before class
#BeforeClass
static public void setup(){
SpringApplication springApplication = new SpringApplicationBuilder()
.sources(MockServerApp.class)
.build();
context = springApplication.run();
}
//shutdown mock server after class
#AfterClass
static public void tearDown(){
SpringApplication.exit(context);
}
#Test
public void test_bad() throws ClientProtocolException, IOException {
// missing parameter
String result = Request.Post(endpoint.getAddress())
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_bad, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, false);
String errorMessage = (String) resultJsonObj.get("errorMessage");
assertEquals(errorMessage.contains("Payload has incorrect amount of parts"), true);
}
#Test
public void test_good() throws ClientProtocolException, IOException {
String result = Request.Post(endpoint.getAddress())
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_good, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), false);
assertEquals(resultJsonObj.containsKey("HasCopay"), true);
assertEquals(resultJsonObj.containsKey("CopayAmount"), true);
assertEquals(resultJsonObj.containsKey("HasCoinsurance"), true);
assertEquals(resultJsonObj.containsKey("CoinsuranceAmount"), true);
assertEquals(resultJsonObj.containsKey("version"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, true);
String version = (String) resultJsonObj.get("version");
assertEquals(version, "0.97");
}
}
I use it in the request.post, I didn't want to hardcode in my IP address and port number.
When I run the test it says
[ERROR] HttpClientTest.test_bad:63 NullPointer
[ERROR] HttpClientTest.test_good:86 NullPointer
But I am not sure why it is null? I am pretty sure I have everything instantiated and the string is clearly populated..
My package structure for my config is com.billing.mockserver and my package structure for my unit test is com.billing.ws.endpoint.
Here is my application.properties
server.port=9119
server.ssl.enabled=false
logging.config=classpath:logback-spring.xml
logging.file=messages
logging.file.max-size=50MB
logging.level.com.nulogix=DEBUG
billing.engine.address=127.0.0.1
billing.engine.port=9119
billing.engine.api.version=0.97
billing.engine.core.name=Patient_Responsibility
You are missing springboot basic understanding. #Configuration class is to initialize other spring beans and other things and are the first classes which get initialized. You should not #Autowire #configuration class.
In your Configuration class you can either create Spring bean for username and password and autowire that in your test class or directly use #Value in your Test class.
Example: in your configuration class you are creating bean of GetVersionEndPoint and you can autowire that in your Test class.
Update 2:
For test classes, you need to add application.properties file in src\test\resource
I have below code for making a POST call to RestAPI for Tableau system, which is working and seeing response output.
However, I would like to capture cookie from this output and need to be used for further consumption! Can somebody help me on this problem?
Code:
package com.abc.it.automation.service;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Properties;
import org.springframework.http.HttpHeaders;
import org.springframework.http.RequestEntity.HeadersBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;
import com.abc.it.automation.utils.SSLUtil;
public class BIaaSTableauService {
private static Properties tableau_properties = new Properties();
static {
// Loads the values from configuration file into the Properties instance
try {
tableau_properties.load(new FileInputStream("res/config.properties"));
} catch (IOException e) {
System.out.println(e);
}
}
private static final String loginURL = tableau_properties.getProperty("server.host");
private static final String siteSearchURL = tableau_properties.getProperty("site.search.url");
public static void main(String[] args) throws KeyManagementException, NoSuchAlgorithmException {
RestTemplate restTableau = new RestTemplate();
String requestLogin = "<tsRequest>"+
"<credentials name=\"svc_tableau\" password=\"xxxxxxxxx\" >"+
"<site contentUrl=\"\"/>"+
"</credentials>"+
"</tsRequest>";
SSLUtil.turnOffSslChecking();
ResponseEntity<String> responseLogin = restTableau.postForEntity(loginURL, requestLogin, String.class);
System.out.println(responseLogin.getBody());
You need to build your RestTemplate as follows.
RestTemplate restTableau = new RestTemplate(new MyClientHttpRequestFactory());
Extend ClientHttpRequestFactory as follows.
public class MyClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
private Cookie cookie;
//setters and getters.
#Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
this.setCookie(connection.getRequestProperty("Cookie"));
}
}