How to read csv data one by one and pass it in multiple testNG tests - csv

I need to insert a data multiple times in an web application. I am using selenium with testNG along with data driven framework.
I am using CSV file for reading the the input values.
Please find the sample code below.
public class TestData
{
private static String firstName;
public static String lastName;
#BeforeClass
public void beforeClass() throws IOException
{
reader = new CSVReader(new FileReader(fileName));
while((record = reader.readNext()) != null)
{
firstName = record[0];
lastName = record[1];
}
}
#Test
public void test1()
{
driver.findElement(By.id(id)).sendKeys(firstName);
driver.findElement(By.id(id)).click();
and so on....
}
#Test
public void test2()
{
driver.findElement(By.id(id)).sendKeys(lastName);
driver.findElement(By.id(id)).click();
and so on....
}
}
Here, I need to insert 3 records, but when I use the above code, only the 3rd record gets inserted.
Kindly help me to fix this issue.
Sample Input File

What you need here is a Factory powered by a DataProvider. The Factory would produce test class instances (A test class here is basically a regular class that contains one or more #Test methods housed in it). The data provider would basically feed the factory method with the data required to instantiate the test class.
Now your #Test methods would basically work with the data members in the instances to run its logic.
Here's a simple sample that shows this in action.
import org.assertj.core.api.Assertions;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class TestClassSample {
private String firstName;
private String lastName;
#Factory(dataProvider = "dp")
public TestClassSample(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#DataProvider(name = "dp")
public static Object[][] getData() {
//feel free to replace this with the logic that reads up a csv file (using CSVReader)
// and then translates it to a 2D array.
return new Object[][]{
{"Mohan", "Kumar"},
{"Kane", "Williams"},
{"Mark", "Henry"}
};
}
#Test
public void test1() {
Assertions.assertThat(this.firstName).isNotEmpty();
}
#Test
public void test2() {
Assertions.assertThat(this.lastName).isNotEmpty();
}
}

As per the data given by you , the while loop ends at the third record of CSV file. In each iteration your variables "firstName" and "lastName" are overwritten.
When the loop breaks , the variables store the lastly written values. So , use a better data structure for storing all values. I recommend map.
You can further club all the test cases in a single method , use invocationcount attribute in #Test annotation to repeat the execution for each entry from map. Add one more method with #BeforeTest for increment to next keyset in map.

Related

Dependecy between two different json files in restassured

I have Created two java classes TestA.java,TestB.java using restAssured where each of the class reads json from TestA.json and testB.json and post a request to endpoint uri.TestA.java returns a json response having tag "customerID" which will be input for one of the tags of TestB.json and when ever I post a request using "TestB.java" customerID has to be picked from TestB.json .How do my code look like?Any ideas?
My code :
TestA.java
String requestBody = generateString("CreateCustomer.json");
RestAssured.baseURI = "https://localhost:8080";
Response res = given().contentType(ContentType.JSON)
.header("Content-Type", "application/json").header("checkXML", "N").body(requestBody).when()
.post("/restservices/customerHierarchy/customers").then().assertThat()
.statusCode(201).and().body("transactionDetails.statusMessage", equalTo("Success")).and().log().all()
.extract().response();
//converts response to string
String respose = res.asString();
JsonPath jsonRes = new JsonPath(respose);
CustomerID = jsonRes.getString("customerNodeDetails.customerId");
TestA.java response
{
"customerNodeDetails": {
"customerId": "81263"
},
Now i want to pass this customerID as input in testB.json or testB.java which is dynamic.
TestB.json
"hierarchyNodeDetails": {
"**customerId**":"",
"accountNumber": "",
"startDate": "",
}
Both TestA.java and TestB.java looks almost same except the post uri
Thanks in Advance
It depends on how you are distributing your classes:
If you want to write the tests for A and B in a single class. Declare a local variable of type Response/String and then store the customer ID in that variable. The scope of the variable will be live in all TestNG methods. You can set the customer ID for the B.json from the local variable.
public class Test{
String _cust_id;
#Test
public void test_A(){
// ceremony for getting customer id
_cust_id = jsonRes.getString("customerNodeDetails.customerId");
}
#Test
public void test_B(){
// write value of customer id using the variable _cust_id
}}
You can try this approach, but would suggest separating the data part to a dataProvider class.
If you want to have separate classes for A and B, use ITestContext to pass values from one class to the other.
public class A{
#Test
public void test1(ITestContext context){
context.setAttribute("key", "value");
}
}
public class B{
#Test
public void test2(ITestContext context){
String _attribute = context.getAttribute(key);
}
}
The elegant way could be, use a dataProvider for class B test where you perform the ceremony of getting the customerID from class A Tests.
public class DataB{
#DataProvider
public static Object[][] _test_data_for_b(){
// get the customerID
// create the json for class B
// return the json required for class B test
// All these could be achieved as everything has a common scope
}}
public class B{
#Test(dataProvider = "_test_data_for_b", dataProviderClass = DataB.class)
public void test_B(String _obj){
// perform the testing
}}

Display Message to User instead of empty JSON on HTML when records are empty in the database

I have an application where I have an html page which takes user input through a textbox.This is a REST Spring Framework and is divided as Controller, Entity, Service, Repository, View and the main application class.
I take an input value and search in the Mongodb database, If the value is present, I return the entity object from Service to Controller. The controller returns the same Entity View object.- PersonView in this case. I get a JSON Data.
The above scenario works well as long as there are records in the database. In case if the record is not present, it returns an empty JSON. My Controller returns Person View Object and I do not wish to change the signature and make the return type as String since in that case it returns the address on my HTML page.
Considering this, how should I handle the case when there are no records in the database and I wish to display a message on this same HTML page saying there are no records available.
I tried throwing an exception but in this case too, how Do I display message on my HTML considering that my Controller returns JSON object and I do not wish to change its signature?
Controller Class is as below:
public PersonView searchPerson(#PathVariable String pname) {
List<Person> pList= PersonService.searchPerson(pname);
PersonView personView = new PersonView();
personView.setPersonView(pList);
return personView;
EDIT:
Here is the function from personView Class that I call in Controller:
public List<Person> setPersonView() {
this.personView = personView;
}
Here is the service Impl class:
public List<Person> searchPerson(String name) throws Exception {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty())
throw new Exception("Records not found in the the database");
return personlist;
}
Create a custom Exception class:
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
}
}
Now, in you controller code:
public List<Person> searchPerson(String name) {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty()) {
throw new EntityNotFoundException("Records not found in the the database");
}
return personlist;
}
After that you can try something like this in you controller class:
private static final MappingJacksonJsonView JSON_VIEW = new MappingJacksonJsonView();
#ExceptionHandler(EntityNotFoundException.class)
public ModelAndView handleNotFoundException( Exception ex )
{
return new ModelAndView(JSON_VIEW, "error", new ErrorMessage("No Record in Db") );
}
Your ErrorMessage class can be a simple POJO:
public class ErrorMessage {
private String message;
ErrorMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
Although already answered, I will add some points here.
Please note that at some point of time you will have a requirement to send the
headers, Response body (with different Objects). So consider using ResponseEntity Object which will be a wrapper to your List. Here is the sample code.
public ResponseEntity<List<Person>> searchPerson(String name) {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty()) {
return new ResponseEntity(new EntityNotFoundException("Records not found in the the database"), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity(personlist , HttpStatus.OK);
}
Response Entity Object provides flexibility to greater extent. Read the documentation here.
https://docs.spring.io/spring/docs/current/javadocapi/org/springframework/http/ResponseEntity.html

How to update preload data in spring when DB record updated

I use Spring and Hibernate for my application and want to load some configuration data from DB when the application launches. But the question is how I can update the preloaded data in case the record in DB is updated (btw, I use mysql for the DB).
I found some solutions said using the trigger in mysql, but I don't know whether the trigger can call some WebService all send some events to tell the application.
Are there some more solutions or good ideas for the case?
Here's the sample code of preloading data:
#Service
public class PreloadService {
#Autowired
private ConfigurationDao configurationDao;
private Map<String, String> preloadConfs = null;
#PostConstruct
public void getConfigurations() {
Map<String, String> results = new HashMap<String, String>();
List<Configuration> confs = configurationDao.findConfigurations(null, null);
for (Configuration c: confs) {
results.put(c.getCode(), c.getDescription());
}
preloadConfs = results;
}
public String getDescription(String code) {
return preloadConfs.get(code);
}
}
and other class should use the class like this
#Autowired
private PreloadService preloadService;
public void foo() {
preloadService.getDescription("code");
}
So the question is how I can update the preloadConfs object if the configuration table was changed?

Hibernate: Storing an fixed length array in one database table row

I have been trying to find a solution to store a fixed length array as a property of an object using hibernate in the same DB table as the object not using a BLOB for the array.
I currently have a class ProductionQCSession which looks like
#Entity
public class ProductionQCSession extends IdEntity {
private Long id;
private Float velocity;
private Float velocityTarget;
private Float[] velocityProfile;
public ProductionQCSession() {
}
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Override
public Long getId() {
return id;
}
#SuppressWarnings("unused")
public void setId(Long id) {
this.id = id;
}
#Basic
public Float getVelocity() {
return velocity;
}
public void setVelocity(Float velocity) {
this.velocity = velocity;
}
#Basic
public Float[] getVelocityProfile() {
return velocityProfile;
}
public void setVelocityProfile(Float[] velocityProfile) {
this.velocityProfile = velocityProfile;
}
}
Ideally I would like the DB structure to be
id|velocity|VPValue0|VPValue1|VPValue2|VPValue3|...
21| 2.1| 0.1| 0.2| -0.1| 0.3|...
I know with a high certainty that we always have 15 items in the velocityProfile array and those values as just as much properties of the object as any other property therefore I think it makes sense to add them to the database table schema, if it's possible. I would prefer to have it this way as it would be easy to get a overview of the data just doing a raw table print.
The current code just stores the array data as a BLOB.
I have looked http://ndpsoftware.com/HibernateMappingCheatSheet.html mapping cheat sheet, but could not seem to find any good solution.
I'm I just trying to do something nobody else would do?
Essentially, you're trying to have a multi-value field, which is not a relational database concept. A normalized solution would put those into a child table, which Hibernate would let you access directly from the parent row (and return it as a collection).
If you are adamant that it should be in a single table, then you'll need to create 15 individual columns....and hope that in the future you don't suddenly need 16.
The solution ended up being using the standardised method of using a child table even though it makes the data analysis slightly more complicated. The following code was used.
#ElementCollection
#CollectionTable(name ="QCVelocityProfile")
public List<Float> getVelocityProfile() {
return velocityProfile;
}
public void setVelocityProfile(List<Float> velocityProfile) {
this.velocityProfile = velocityProfile;
}

Junit testing for a class with strings

//DOC Datatype Constants
public enum DocDatatype {
PROFILE("Profile"),
SUPPORT_DETAIL("SupportDetail"),
MISC_PAGE("MiscPage"),
String name;
DocDatatype(String name) {
this.name = name;
}
public String getName() {
return name;
}
// the identifierMethod
public String toString() {
return name;
}
// the valueOfMethod
public static DocDatatype fromString(String value) {
for (DocDatatype type : DocDatatype.values()) {
if (type.getName().equals(value))
return type;
}
throw new java.lang.IllegalArgumentException(value
+ " is Not valid dmDataType");
}
}
I have written the junit test case in this way. Whether it is right way to write or wrong way...?
public class DocDatatypeTest {
private static final Log logger = LogFactory
.getLog(TreeConstantTest.class);
#Test
public void testDocDatatypeFromName()
{
DocDatatype d= DocDatatype.fromString("Profile");
assertTrue((d.toString().compareToIgnoreCase("PROFILE") == 0));
}
#Test
public void testDocDatatypeFromName1()
{
DocDatatype d = DocDatatype.fromString("SupportDetail");
assertTrue((d.toString().compareToIgnoreCase("SUPPORT_DETAIL") == 0 ));
}
}
}
A few things here:
Remove the logger from the test. A test should pass or fail, no need for logging
Don't use assertTrue for this. If the test fails it will give you no information about /why/ it failed.
I would change this to
#Test
public void testDocDatatypeFromName()
{
DocDatatype actualDocType = DocDatatype.fromString("Profile");
assertSame(DocDataType.PROFILE, actualDocType);
}
If you really want to assert that value of the toString then do this
#Test
public void testDocDatatypeFromName()
{
DocDatatype d= DocDatatype.fromString("Profile");
assertEquals("Profile", d.toString());
}
You're missing tests for when the lookup doesn't match anything
I wouldn't even write these tests as I see them adding no value whatsoever. The code that uses the enums should have the tests, not these.
Your tests are named very badly. There's no need to start a test with test and the fact you add a "1" to the end of the second test should tell you something. Test names should focus on action and behaviour. If you want to read more about this, get the December issue of JAX Magazine which has a snippet about naming from my forthcoming book about testing.