I'm working on API testing automation using Rest assured. I would like to store Response as an object after calling an API so I can validate some data using that object like, status code, body, header and all.
I tried using System.setPropery but it allows to store only String and if store Response as String like System.setProperty("test", response.toString()); and try to retrieve System.getProperty("test"); then throws the error
java.lang.ClassCastException: java.lang.String cannot be cast to
io.restassured.response.Response
It there a way to store an object somewhere and access it for later use?
Don't use System.Properties for this purpose.
Please use a simple cache store as given below.
public class ResponseCache {
private static final ResponseCache myInstance = new ResponseCache();
private final Map<String, Response> cacheStore = new HashMap<>();
private ResponseCache() {
}
public static ResponseCache getInstance() {
return myInstance;
}
public void addResponse(String key, Response value) {
cacheStore.put(key, value);
}
public boolean exists(String key) {
return cacheStore.containsKey(key);
}
public void remove(String key) {
if (exists(key)) {
cacheStore.remove(key);
}
}
public Response get(String key) {
return exists(key) ? cacheStore.get(key) : null;
}
}
Once your execution work is completed you can remove that key.
Related
I apologize if this has been answered before but either i don't know the correct verbiage or my google fu is bad.
I have a TestModel class which has the getters and setters for all the tests I use. Then I have a AdditionalTestModel class that extends the TestModel with additional getters and setters for that specific type of tests.
Now I have BuildTest Class that i want to be able to pass TestModel and any extended classes of TestModel.
public static Class<?> buildTest(Class<?> test, Class<?> template)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Class<?> testClass = test.getClass();
Method[] testMethods = testClass.getMethods();
for (Method method : testMethods) {
String name = method.getName();
if (name.startsWith("get")) {
String testMethodType = method.getReturnType().getTypeName();
// additional code removed//
}
}
If instead of Class<?> i was using TestModel it would work for any test that i pass of Class type TestModel. But i want to be able to pass the extended class to this method as well without having to write a method for each extended class. Any recommendations?
Adding information on the models in case it matters.
public class TestModel {
private String testDescription;
private String testName;
private String apiPath;
private String method;
private String expectedTest;
private Map<String, String> header = new HashMap<>();
private Object body;
private String expectedResult;
private String testCaseId;
private String testUUID;
private List testTypes;
public String getTestDescription() {
return testDescription;
}
public void setTestDescription(String testDescription) {
this.testDescription = testDescription;
}
public String getTestName() {
return testName;
}
public void setTestName(String testName) {
this.testName = testName;
}
public String getAPIPath() {
return apiPath;
}
public void setAPIPath(String apiPath) {
this.apiPath = apiPath;
}
public String getExpectedTest() {
return expectedTest;
}
public void setExpectedTest(String testName) {
this.expectedTest = testName;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Map<String, String> getHeader() {
return header;
}
public void setHeader(Map<String, String> header) {
this.header = header;
}
public Object getBody() {
return body;
}
public void setBody(Object body) {
this.body = body;
}
public String getExpectedResult() {
return expectedResult;
}
public void setExpectedResult(String expectedResult) {
this.expectedResult = expectedResult;
}
public String getTestCaseId() {
return testCaseId;
}
public void setTestCaseId(String testCaseId) {
this.testCaseId = testCaseId;
}
public String getTestUUID() {
return testUUID;
}
public void setTestUUID(String testUUID) {
this.testUUID = testUUID;
}
public List getTestTypes() {
return testTypes;
}
public void setTestTypes(List testTypes) {
this.testTypes = testTypes;
}
}
public class AdditionalTestModel extends TestModel {
#Override public Object getBody() {
return super.getBody();
}
}
Edit: per a request adding the call information here:
#Test(dataProvider = "Default", threadPoolSize = THREADS, timeOut = API_TIME_OUT)
#Description("")
public void sampleTest(AdditionalTestModel testFromDataProvider) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
testSetup(testFromDataProvider);
AdditionalTestModel test = BuildTest.buildTest(testFromDataProvider, template);
Response response = RestAPI.call(test, testEnvironment);
if (null != response) {
ValidateAPIResponse.validateTestModel(test, response);
} else {
Assert.fail("Response is null, probably a bad method.");
}
}
Where testFromDataProvider is passed from a TestNg data provider.
Now LppEdd below already pointed out i could only assign the base class using generics so working on trying it his way, just have not gotten a chance to change things up yet.
Edit: Also realize now my question was bad. Thanks LppEdd. I should have asked How can I get a method to accept an instance of a class and an instance of any extended class
You are close, you just need to use the extends modifier.
If the class passed in as the test and template parameter should be the same exact class type, you can do:
public static <T extends TestModel> Class<T> buildTest(Class<T> test, Class<T> template) { ... }
Otherwise you can do
public static Class<? extends extends TestModel> buildTest(Class<? extends TestModel> test, Class<? extends String> extends TestModel) { ... }
Which will allow different types to be returned and passed in to each parameter.
You can read up on Java generics and wilcards starting here: https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
Your buildTest method must accept a TestModel class.
You might be looking for something like
public static TestModel buildTest(
final TestModel test,
final TestModel template) {
final Class<? extends TestModel> testClass = test.getClass();
final Method[] testMethods = testClass.getMethods();
for (final Method method : testMethods) {
final String name = method.getName();
if (name.startsWith("get")) {
final String testMethodType = method.getReturnType().getTypeName();
// additional code removed
}
}
// Maybe
return yourNewInstance; // yourNewInstance is a TestModel, or any class extending it
}
The template argument seems unused here (clarify).
What's the wanted return type? (clarify)
Usage example
final TestModel value1 = buildTest(new TestModel(), ...);
final TestModel value2 = buildTest(new AdditionalTestModel(), ...);
This looks to be exactly the same problem as must be solved by test frameworks. For example, see junit (https://junit.org/junit5/).
The core problem is how to obtain the collection of test methods of a class.
A direct solution would be to have the test class be required to answer its test methods, say, Collection<Function<Void, Void>> getTests(); This has several problems, one being that sub-classes must explicitly list their test methods, two being that sub-classes must be careful to add in the test methods from their super-class, and third, this really fits more as static behavior, which would try to shift java instance typing to the class layer, which just isn't supported by java.
An indirect solution would be to require that test methods satisfy a particular pattern (for example, must start with "test" and have no parameters), and use reflection to discover the methods. Or, use an annotation (say, #Test, which is what junit does) to mark out test methods, and again use the java reflection API to discover methods with the marker.
I have the following Java class that is uploaded on Amazon's Lambda service:
public class DevicePutHandler implements RequestHandler<DeviceRequest, Device> {
private static final Logger log = Logger.getLogger(DevicePutHandler.class);
public Device handleRequest(DeviceRequest request, Context context) {
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.defaultClient();
DynamoDBMapper mapper = new DynamoDBMapper(client);
if (request == null) {
log.info("The request had a value of null.");
return null;
}
log.info("Retrieving device");
Device deviceRetrieved = mapper.load(Device.class, request.getDeviceId());
log.info("Updating device properties");
deviceRetrieved.setBuilding(request.getBuilding());
deviceRetrieved.setMotionPresent(request.getMotionPresent());
mapper.save(deviceRetrieved);
log.info("Updated device has been saved");
return deviceRetrieved;
}
}
I also have an Execution Role set that gives me complete control over DynamoDB. My permissions should be perfectly fine since I've used the exact same permissions with other projects that used Lambda and DynamoDB in this exact manner (the only difference being a different request type).
The intended point of this class is to have it be called by API Gateway (API Gateway -> Lambda -> DynamoDB), but for now I simply am trying to test it on Lambda (Lambda -> DynamoDB).
For reference, in case it matters, here is the DeviceRequest class:
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "deviceId", "building", "motionPresent" })
public class DeviceRequest {
#JsonProperty("deviceId")
private String deviceId;
#JsonProperty("building")
private String building;
#JsonProperty("motionPresent")
private Boolean motionPresent;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonProperty("deviceId")
public String getDeviceId() {
return deviceId;
}
#JsonProperty("deviceId")
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
#JsonProperty("building")
public String getBuilding() {
return building;
}
#JsonProperty("building")
public void setBuilding(String building) {
this.building = building;
}
#JsonProperty("motionPresent")
public Boolean getMotionPresent() {
return motionPresent;
}
#JsonProperty("motionPresent")
public void setMotionPresent(Boolean motionPresent) {
this.motionPresent = motionPresent;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
And here is the Device class:
#DynamoDBTable(tableName="DeviceTable")
public class Device {
private String deviceID;
private String building;
private String queue;
private boolean motionPresent;
#DynamoDBHashKey(attributeName="Device ID")
public String getDeviceID() {
return deviceID;
}
public void setDeviceID(String deviceID) {
this.deviceID = deviceID;
}
#DynamoDBAttribute(attributeName="Motion Present")
public boolean getMotionPresent() {
return motionPresent;
}
public void setMotionPresent(boolean motionPresent) {
this.motionPresent = motionPresent;
}
#DynamoDBAttribute(attributeName="Building")
public String getBuilding() {
return this.building;
}
public void setBuilding(String building) {
this.building = building;
}
#DynamoDBAttribute(attributeName="Queue")
public String getQueue() {
return this.queue;
}
public void setQueue(String queue) {
this.queue = queue;
}
}
Here is the JSON input that I'm trying to test the Lambda with:
{
"deviceId": "test_device_name",
"building": "building1",
"motionPresent": false
}
No exceptions whatsoever are thrown (I've tried wrapping it around a try/catch block) and the lambda timing out is the only thing that happens. I've tried using log/print statements at the very beginning prior to the initialization of the DynamoDB client to see if the request can be read properly and it does appear to properly parse the JSON fields. I've also separated the client builder out and found that the builder object is able to be initialized, but the timing out comes from when the builder calls build() to make the client.
If anyone has any insight into why this timing out is occurring, please let me know!
Turns out that by bumping up the timout period AND the allotted memory, the problem get solved. Not sure why it works since the lambda always indicated that its memory usage was under the previously set limit, but oh well. Wish that in the future Amazon will provide better error feedback that indicates if a lambda needs more resources to run.
I am attempting to store JSON in a postgresql 9.4 database using the JSONB datatype with dropwizard and jdbi. I am able to store the data, but if my json goes any deeper than a single level, the json gets turned into a string instead of nested json.
For instance, the following json
{
"type":"unit",
"nested": {
"key":"embedded"
}
}
actually gets stored as
{
"type":"unit",
"nested":"{key=embedded}"
}
The method signature in my DAO is
#SqlUpdate("insert into entity_json(id, content) values(:id, :content\\:\\:jsonb)")
protected abstract void createJson(#Bind("id") String id, #Bind("content") Map content);
I obviously have something wrong, but I can't seem to figure out the correct way to store this nested data.
You can use PGObject to build a JSONB data type in Java. This way you can avoid any special handling as part of the SQL:
PGobject dataObject = new PGobject();
dataObject.setType("jsonb");
dataObject.setValue(value.toString());
A full example including converting an object to a tree, and using an ArgumentFactory to convert it to a PGobject could look like this:
public class JsonbTest {
#Test
public void tryoutjson() throws Exception {
final DBI dbi = new DBI("jdbc:postgresql://localhost:5432/sighting", "postgres", "admin");
dbi.registerArgumentFactory(new ObjectNodeArgumentFactor());
Sample sample = dbi.onDemand(Sample.class);
ObjectMapper mapper = new ObjectMapper();
int id = 2;
User user = new User();
user.emailaddress = "me#home.com";
user.posts = 123;
user.username = "test";
sample.insert(id, mapper.valueToTree(user));
}
public static class User {
public String username, emailaddress;
public long posts;
}
public interface Sample {
#SqlUpdate("INSERT INTO sample (id, data) VALUES (:id, :data)")
int insert(#Bind("id") long id, #Bind("data") TreeNode data);
}
public static class ObjectNodeArgumentFactor implements ArgumentFactory<TreeNode> {
private static class ObjectNodeArgument implements Argument {
private final PGobject value;
private ObjectNodeArgument(PGobject value) {
this.value = value;
}
#Override
public void apply(int position,
PreparedStatement statement,
StatementContext ctx) throws SQLException {
statement.setObject(position, value);
}
}
#Override
public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
return value instanceof TreeNode;
}
#Override
public Argument build(Class<?> expectedType, TreeNode value, StatementContext ctx) {
try {
PGobject dataObject = new PGobject();
dataObject.setType("jsonb");
dataObject.setValue(value.toString());
return new ObjectNodeArgument(dataObject);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
I was able to solve this by passing in a string obtained by calling writeValueAsString(Map) on a Jackson ObjectMapper. My createJson method turned into:
#SqlUpdate("insert into entity_json(id, content) values(:id, :content\\:\\:jsonb)")
public abstract void createJson(#Bind("id")String id, #Bind("content")String content);
and I obtained the string to pass in by creating a mapper:
private ObjectMapper mapper = Jackson.newObjectMapper();
and then calling:
mapper.writeValueAsString(map);
This gave me the nested json I was looking for.
I would like to store some field of type ParentClass as json string into my database. I don't want to use Serializable interface and DataType.SERIALIZABLE cause it ties with full class name of serialized class.
So I'm using the following code:
class ParentClass {
#DatabaseField(persisterClass = MyFieldClassPersister.class)
private MyFieldClass myField;
}
where persister class a kind of:
public class MyFieldClassPersister extends StringType {
private static final MyFieldClassPersister singleTon = new MyFieldClassPersister();
public static MyFieldClassPersister getSingleton() {
return singleTon;
}
protected MyFieldClassPersister() {
super(SqlType.STRING, new Class<?>[0]);
}
#Override
public Object parseDefaultString(FieldType fieldType, String defaultStr) {
return jsonStringToObject(defaultStr);
}
#Override
public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
String string = results.getString(columnPos);
return jsonStringToObject(string);
}
private static MyFieldClass jsonStringToObject(String string) {
// json to object conversion logic
}
}
Here are two issues I've met:
I didn't get how to specify custom convertion from object to string. Seems that ORMLite calls Object.toString() in order to get string representation of the object. It would be great to have some method in Persister in which I could specify how to convert Object to string (json in my case). Yes, I can override toString() method in MyFieldClass, but it is more convenient to perform conversion in Persister. Is there any method I could override in order to specify convertion from model object to db-object?
If I mark my custom field type as String type:
class ParentClass {
#DatabaseField(dataType = DataType.STRING, persisterClass = MyFieldClassPersister.class)
private MyFieldClass myField;
}
then ormlite crashes when saving object with the following message:
java.lang.IllegalArgumentException: Field class com.myapp.venue.MyFieldClass for
field FieldType:name=myField,class=ParentClass is not valid for type
com.j256.ormlite.field.types.StringType#272ed83b, maybe should be
class java.lang.String
It doesn't crash if I omit dataType specification. Can I avoid this crash in some way? It seems to me that it's better to specify types explicitly.
So basically your persister should be implemented in the next way:
public class MyFieldClassPersister extends StringType {
private static final MyFieldClassPersister INSTANCE = new MyFieldClassPersister();
private MyFieldClassPersister() {
super(SqlType.STRING, new Class<?>[] { MyFieldClass.class });
}
public static MyFieldClassPersister getSingleton() {
return INSTANCE;
}
#Override
public Object javaToSqlArg(FieldType fieldType, Object javaObject) {
MyFieldClass myFieldClass = (MyFieldClass) javaObject;
return myFieldClass != null ? getJsonFromMyFieldClass(myFieldClass) : null;
}
#Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
return sqlArg != null ? getMyFieldClassFromJson((String) sqlArg) : null;
}
private String getJsonFromMyFieldClass(MyFieldClass myFieldClass) {
// logic here
}
private MyFieldClass getMyFieldClassFromJson(String json) {
// logic here
}
}
You should register it in onCreate method of your OrmLiteSqliteOpenHelper class
#Override
public void onCreate(SQLiteDatabaseHolder holder, ConnectionSource connectionSource) {
try {
//...
DataPersisterManager
.registerDataPersisters(MyFieldClassPersister.getSingleton());
} catch (SQLException e) {
// log exception
}
}
And then you can use it in your model like this:
#DatabaseField(persisterClass = MyFieldClassPersister.class, columnName = "column_name")
protected MyFieldClass myFieldClass;
Don't register the persister adapter in the onCreate() method. This method only gets called when your database is first created. You should add this somewhere else, like your constructor or onOpen() method.
I'm trying to find the best OO way to do this, and I would appreciate your help on it.
I think the simplest way is to show you how I've done it and try to explain what I want after (I simplified it) :
abstract public class MyServiceApi {
private static MyServiceApi instance = null;
public static <T extends MyServiceApi> T getInstance(Class<T> cls) {
if (instance == null) {
try {
instance = cls.newInstance();
}
catch (InstantiationException e) {}
catch (IllegalAccessException e) {}
}
return (T) instance;
}
private private HashMap<String, String> headers;
protected MyServiceApi() {}
public HashMap<String, String> getHeaders() {
return headers;
}
public void setHeaders(HashMap<String, String> headers) {
this.headers = headers;
}
protected <T extends IMyServiceApiResponse> T send(String url, IMyServiceApiRequest request, Class<T> to) {
// Do some stuffs
// IMPORTANT : Also set headers to the request
}
protected String getBaseUrl() {
return "http://api.mywebsite.com/";
}
}
public class UsersApi extends MyServiceApi {
public static UsersApi getInstance() {
return getInstance(UsersApi.class);
}
protected UsersApi() {
super();
}
#Override
protected String getBaseUrl() {
return super().getBaseUrl() + "Users/";
}
// mutliple function that calls a specific URL in the API, and return specifics object based on the call, for example :
public MyServiceApiUsersResponse getUsers(MyServiceApiUsersRequest request) {
return send(getBaseUrl() + "get", request, MyServiceApiUsersResponse.class);
}
}
public class ItemsApi extends MyServiceApi {
public static ItemsApi getInstance() {
return getInstance(ItemsApi.class);
}
protected ItemsApi() {
super();
}
#Override
protected String getBaseUrl() {
return super().getBaseUrl() + "Items/";
}
// mutliple function that calls a speicfic URL in the API, and return specifics object based on the call, for example :
public MyServiceApiItemsResponse getUsers(MyServiceApiItemsRequest request) {
return send(getBaseUrl() + "get", request, MyServiceApiItemsResponse.class);
}
}
Now that you have the idea, I'm stuck for something.
First of all, I don't know if what I did is correct (in a Java OO way). I think it's not bad, but I lack the experience to be sure.
Second of all, once my project is running, MyServiceApi will keep the same headers, I won't call other API or with other credentials. That's why I thought about the Singleton : I set the headers at my application start, and then I just have to do the request.
But I believe having UsersApi and ItemsApi extending MyServiceApi is the best way to do. They use MyServiceApi, they don't extends its capabilities.
Also, I eard that SingleTon are anti-pattern, bad for tests, etc.
So now I'm loose and I don't know what to do. How would you do that?
A possible idea is to remove the abstract of MyServiceApi and set a Singleton on it, having UsersApi and ItemsApi to use MyServiceApi but not by extending it, but how would I manage the getBaseUrl then ?
Thank you really much for your help, I really appreciate!
Use Dependency Injection rather than a Singleton.
It looks like you're trying to have a single service that has a base URL and sets up your headers.
Using Dependency Injection, create a service called MyApiService, much like you have and have UsersApi and ItemsApi depend on it as in:
public class MyServiceApi {
private final String baseUrl;
private final HashMap<String, String> headers;
protected MyServiceApi(String baseUrl, HashMap<String, String> headers) {
this.baseUrl = baseUrl;
this.headers = headers;
}
protected <T extends IMyServiceApiResponse> T send(String url,
IMyServiceApiRequest request, Class<T> to) {
// Do some stuffs
// IMPORTANT : Also set headers to the request
}
protected String getBaseUrl() {
return baseUrl;
}
}
public class UsersApi {
private final MyServiceApi myServiceApi;
protected UsersApi(MyServiceApi myServiceApi) {
this.myServiceApi = myServiceApi;
}
protected String getBaseUrl() {
return myServiceApi.getBaseUrl() + "Users/";
}
// mutliple function that calls a specific URL in the API, and return
// specifics object based on the call, for example :
public MyServiceApiUsersResponse getUsers(
MyServiceApiUsersRequest request) {
return myServiceApi.send(getBaseUrl() + "get", request,
MyServiceApiUsersResponse.class);
}
}
A few other things you could do:
Create an interface that both MyServiceApi and UsersApi implements if you want to expose getBaseUrl consistently
Have a look at some of the information about Dependency Injection out there
This is how I would write it
enum MyServiceApi {
UsersApi {
public MyServiceApiUsersResponse getUsers(MyServiceApiUsersRequest request) {
return send(getBaseUrl() + "Users/get", request, MyServiceApiUsersResponse.class);
}
}, ItemsApi {
// mutliple function that calls a speicfic URL in the API, and return specifics object based on the call, for example :
public MyServiceApiItemsResponse getUsers(MyServiceApiItemsRequest request) {
return send(getBaseUrl() + "Items/get", request, MyServiceApiItemsResponse.class);
}
};
private final Map<String, String> headers = new LinkedHashMap<String, String>();
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(HashMap<String, String> headers) {
this.headers.clear();
this.headers.putAll(headers);
}
public abstract <T extends IMyServiceApiResponse> T send(String url, IMyServiceApiRequest request, Class<T> to);
protected String getBaseUrl() {
return "http://api.mywebsite.com/";
}
}
This is just for your awareness. If you are using Singleton pattern your getInstance method should be synchronized. Think a scenario where you have multiple threads running.For an example if one thread checked the instance is null and since it is null it will go inside the try block.Lets say it halts and the second thread comes to running state. And still the instance is null and it also have the opportunity to go inside the try block. then ultimately you will end up with two instances and you Singleton strategy will break