Access JBehave Examples table data in step - java

I would like to know if there is a way I can access examples table row data within a step method without passing it in as an argument?
Story file:
Given I am logged in
When I create a trade
Then a trade should be created
Examples:
|data1|data2|
|11111|22222|
|33333|44444|
Step file:
#When("I create a trade")
public void createTrade(#Named("data1") String data1, #Named("data2") String data2){
//code to create trade using data1 and data2
}
Above works fine, but I would like a way to access the data row from the examples table within the method. (The reason I would like to do this is because all columns may not be present in the examples table in every story, and I have found that if I have say 3 * #Named as parameters in the step method, but one of these are missing from the actual examples table then it fails to run.)
#When("I create a trade")
public void createTrade(){
//check if there is a data1 column, if so get value and do something
//check if there is a data2 column, if so get value and do something
}
Thanks for your help

You can implement a new parameter converter, and then pass the table as an object.
for example, in our project we built ExamplesTableConverter (note: there is an our of the box JBehave converter that we didn't test):
public class ExamplesTableConverter extends ParameterConverters.ExamplesTableConverter {
private final ExamplesTableFactory factory;
private static final String ROW_SEPARATOR = "\n";
private static final String FIELD_SEPARATOR = "|";
public ExamplesTableConverter(){
this(new ExamplesTableFactory());
}
public ExamplesTableConverter(ExamplesTableFactory factory){
this.factory = factory;
}
#Override
public boolean accept(Type type) {
if (type instanceof Class<?>){
return ExamplesTable.class.isAssignableFrom((Class<?>) type);
}
return false; //To change body of implemented methods use File | Settings | File Templates.
}
#Override
public Object convertValue(String tableAsString, Type type) {
System.out.println(tableAsString);
String[] rows = tableAsString.split(ROW_SEPARATOR);
StringBuffer resultString = new StringBuffer();
resultString.append(rows[0]);
resultString.append(ROW_SEPARATOR);
for(int i=1; i<rows.length; i++){
String originRow = rows[i];
List<String> rowValues = TableUtils.parseRow(originRow, FIELD_SEPARATOR, true);
String translatedRow = translateRow(rowValues);
resultString.append(translatedRow);
resultString.append(ROW_SEPARATOR);
}
System.out.println(resultString.toString());
Object table = factory.createExamplesTable(resultString.toString());
return table;
//return null;
}
private String translateRow(List<String> rowValues) {
StringBuffer result = new StringBuffer(FIELD_SEPARATOR);
for(String field : rowValues){
try{
result.append(translate(field));
result.append(FIELD_SEPARATOR);}
catch (LocalizationException e){
e.printStackTrace();
//Need do something here to handle exception
}
}
return result.toString();
}
}
then you need to add that converter to your configuration:
configuration.parameterConverters().addConverters(new ExamplesTableConverter());
create a method that use it
#When("create parameters of type $param1 from the next table: $table")
public void doThis(#Named("param1") String param1, #Named("table") ExamplesTable table)
and last, use it in a story:
When create parameters of type type1 from the next table:
|FirstName|LastName|
|Donald|Duck|
this would allow you to iterate the table.
following blog post can also help you
Simpler JBehave Examples Table Processing

Scenario:-
Given data insert in DemoSheet
|demoNumber|demoName|
|101|Demo1|
|102|Demo2|
|103|Demo3|
|104|Demo4|
|105|Demo5|
java class to fetch value from scenario:-
#Given("data insert in DemoSheet $parameterTable")
public void setDataToSheet(ExamplesTable parametersTable)
throws RowsExceededException, WriteException, IOException {
List<String> demonum = new ArrayList<String>();
List<String> demoname = new ArrayList<String>();
for (Map<String, String> row : parametersTable.getRows()) {
Iterator it = row.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry) it.next();
if (pairs.getKey().equals("demoNumber")) {
demonum.add((String) pairs.getValue());
} else if (pairs.getKey().equals("demoName")) {
demoname.add((String) pairs.getValue());
}
}
}
for(String s:demonum)
{
System.out.println(s.getDemonum);
System.out.println(s.getDemoname);
}
}
We can fetch the multiple row using the Example table parameter here i am passing multiple row from scenario to java class..

Related

Call same step with different type of argument in BDD

I'm writing testcases using BDD. I have a scenario where I'm stuck
I'm generating random data using below step
When generate random data for registration form
There is Bean class which have some fields like fname, lname, email, pass while i call above step it generates random data and filled in that bean class
Now it returns that bean class object and I'm storing that in formdata variable
And store into 'formdata'
Now i want to send that to my username field like below
And enter firstname as '${formdata}'
code step for same :
#QAFTestStep(stepName = "enterFirstName", description = "enter firstname as {0}")
public void enterFirstName(Map<String, Object> data) {
sendKeys(data.get("firstname").toString(), element);
}
Its working fine but suppose in some case i have to send only string as below
And enter firstname as 'Narendra'
Step would be :
#QAFTestStep(stepName = "enterFirstName", description = "enter firstname as {0}")
public void enterFirstName(String fname) {
sendKeys(fname, element);
}
Then how do i manage these 2 code as single method ?
I had a similar need for generating random strings for a broader input coverage. I would suggest forming a logic based on delimiters.
Example:
public static void main(String[] arg) {
enterFirstName("iamkenos");
enterFirstName("${formdata}");
}
public static void enterFirstName(String fname) {
System.out.println(transformData(fname));
}
public static String transformData(String data) {
Pattern pattern = Pattern.compile("^\\$\\{.+}$");
Matcher matcher = pattern.matcher(data);
if (matcher.matches()) {
//do some logic on your data;
data = "my new data 123";
}
return data;
}
This will however require you to:
call the transformData(arg) every time
stick to a fixed delimeter e.g. ${}
Output:
iamkenos
my new data 123
I tried below solution which helped me to do the same as i expecting:
#QAFTestStep(stepName = "enterFirstName", description = "enter firstname as {0}")
public void enterFirstName(Object obj) {
if (obj instanceof LinkedTreeMap) {
Map<String, Object> map = (Map<String, Object>) obj;
sendKeys(map.get("firstname").toString(), "regpage.firstname.textbox");
} else if (obj instanceof String) {
sendKeys(obj.toString(), "regpage.firstname.textbox");
} else if (obj instanceof RandomRegisterDataGenerator) {
RandomRegisterDataGenerator data = (RandomRegisterDataGenerator) obj;
sendKeys(data.getFirstname(), "regpage.firstname.textbox");
}
}
Have you looked into form-data-bean? It is preferred, where you can populate bean with one filed or all field and it will fill UI accordingly.
You can have step to populate bean and fill UI inside your bean class like below:
//Object obj: argument can be string or map or json string or xml key
#QAFTestStep( description = "fill registration form using {data}")
public void fillRegistrationFormWithData(Object obj) {
this.fillData(obj);
this.fillUiElements();
}
#QAFTestStep( description = "fill registration form with random data")
public void fillRegistrationFormWithRandomData() {
this.fillRandomData();
this.fillUiElements();
}

How to get back a DTO Object from a procedure

I need to execute a procedure on my sql server database that will return me some fields and I wish to transform this fields directly in a List of my DTO Object that will be returned, but i'm new on spring boot and can't get it to work. I tried to do a Converter class but didnt understand much of how it works e probally did it wrong, here is my code on a way i wish it work:
public interface IMyDtoRepository extends JpaRepository<SomeEntity, Long> {
#Query(value = "EXECUTE MyProcedure :param1, :param2, :param3, :param4, :param5)")
public List<MyDtoObject> execMyProcedure(#Param(value = "param1") Integer param1,
#Param(value = "param2") String param2,
#Param(value = "param3") String param3,
#Param(value = "param4") String param4,
#Param(value = "param5") Integer param5);
}
The DtoObject
public class MyDtoObject{
// My Declared Fields...
public MyDtoObject() {
}
public MyDtoObject(/* My Fields */) {
// Setting fields
}
public MyDtoObject(Object[] objects) {
// Setting fields
}
// Getters n Setters...
I omitted the information that i didn't think it was necessary but i can give more explanation if need it
to map the result on your DtoObject with spring-data-jpa your can use : #SqlResultSetMapping
javadoc here
I have a similar method that I use in my DAL. It uses reflection and generics to convert a datatable to whatever type you pass in. Just pass in the datatable you get as a result of your procedure and you're good to go.
public List<T> ConvertDataToTypeList<T>(System.Data.DataTable DataTable) where T : class, new()
{
try
{
System.Type t_Object_Type = typeof(T);
ICollection<PropertyInfo> p_Properties;
lock (Properties_Dictionary)
{
if (!Properties_Dictionary.TryGetValue(t_Object_Type, out p_Properties))
{
p_Properties = t_Object_Type.GetProperties().Where(property => property.CanWrite).ToList();
Properties_Dictionary.Add(t_Object_Type, p_Properties);
}
}
System.Collections.Generic.List<T> l_List = new List<T>(DataTable.Rows.Count);
foreach (var v_Row in DataTable.AsEnumerable())
{
T o_Object = new T();
foreach (var prop in p_Properties)
{
var propType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
var safeValue = v_Row[prop.Name] == null ? null : Convert.ChangeType(v_Row[prop.Name], propType);
prop.SetValue(o_Object, safeValue, null);
}
l_List.Add(o_Object);
}
return l_List;
}
catch
{
return new List<T>();
}
}

Getting MapReduce results on RIAK (using the Java client)

I am storing Person POJOs (4 string fields - id, name, lastUpdate, Data) on RIAK, then trying to fetch these objects with MapReduce.
I am doing it very similar to Basho documentation:
BucketMapReduce m = riakClient.mapReduce("person");
m.addMapPhase(new NamedJSFunction("Riak.mapByFields"), true);
MapReduceResult result = m.execute();
Collection<Person> tmp = result.getResult(Person.class);
the Person's String constructor is invoked:
public Person(String str){}
(I must have this constructor, otherwise I get an exception for it is missing)
In there I get the object as a String - the Object's fields in one string with a strange delimiter.
why am I not getting the object automatically converted to my POJO? do I really need to go over the string and deserialize it? am i doing something wrong?s
The JS function you're using doesn't do what you think it does :) It selects objects based on a field with a specific value you have to supply as an argument to the phase.
I think what you're looking for is mapValuesJson which will do what you seem to be wanting to do.
Also, you don't need a constructor at all in your POJO.
The code below should point you in the right direction (obviously this is super-simple with all public fields in the POJO and no annotations):
public class App {
public static void main( String[] args ) throws IOException, RiakException
{
IRiakClient client = RiakFactory.httpClient();
Bucket b = client.fetchBucket("test_mr").execute();
b.store("myobject", new Person()).execute();
IRiakObject o = b.fetch("myobject").execute();
System.out.println(o.getValueAsString());
BucketMapReduce m = client.mapReduce("test_mr");
m.addMapPhase(new NamedJSFunction("Riak.mapValuesJson"), true);
MapReduceResult result = m.execute();
System.out.println(result.getResultRaw());
Collection<Person> tmp = result.getResult(Person.class);
for (Person p : tmp)
{
System.out.println(p.data);
}
client.shutdown();
}
}
class Person
{
public String id = "12345";
public String name = "my name";
public String lastUpdate = "some time";
public String data = "some data";
}

Write Java Comparator

I have created a Vector object to store data in Table object as Vector<Table>. Vector<Table> contains components as below.
[Vector<Record> records, String tableName, String keyColumnName, int recordCount, int columnCount]
I need to sort tableName in above Vector to my own order and return Vector<Table> with sorted tableNames for other processes.
I have wrote method as below.
private Vector<Table> orderTables(Vector<Table> loadTables) {
List<String> tableNames = new ArrayList<String>();
for (Table table : loadTables) {
String tblName = table.getTableName();
tableNames.add(tblName);
}
Collections.sort(tableNames, new MyComparable());
return null;
}
But I have no idea about how to write Comparator to this. My own sort order is stored in .properties file. I can read it and get value. But I have no idea about how to compare it.
How could I do it?
Before clarification
You need to write a Comparator for Table objects that delegates to the tableName's comparator:
new Comparator<Table>() {
#Override public int compare(Table one, Table two) {
return one.getTableName().compareTo(two.getTableName());
}
}
Note that this will consider Tables that have the same name to be equal. This can mess things up if you put these tables in a HashMap or HashSet. To avoid this, you can detect this case and return one.hashCode() - two.hashCode() if the table names are the same.
Guava's ComparisonChain is a convenient way to write such multi-stage comparisons:
new Comparator<Table>() {
#Override public int compare(Table one, Table two) {
return ComparisonChain.start()
.compare(one.getTableName(), two.getTableName())
.compare(one.hashCode(), two.hashCode())
.result();
}
}
After clarification
Okay, the question is to impose a predefined sorting order rather than sorting the Tables by name. In that case, you need to make a Comparator that is aware of the ordering defined in the .properties file.
One way to achieve this is to initialize a mapping of table names to sorting order indices, and refer that mapping during the comparison. Given the property value:
SORT_ORDER = SALES,SALE_PRODUCTS,EXPENSES,EXPENSES_ITEMS
The mapping should look like:
{
SALES: 0,
SALE_PRODUCTS: 1,
EXPENSES: 2,
EXPENSES_ITEMS: 3
}
Here's what the comparator would look like:
private static class PredefinedOrderComparator implements Comparator<Table> {
public PredefinedOrderComparator() {
// Initialize orderIndex here
}
private final Map<String, Integer> orderIndex;
#Override public int compare(Table one, Table two) {
return orderIndex.get(one.getTableName()) - orderIndex.get(two.getTableName());
}
}
To populate orderIndex from the property value, you need to:
Get the comma-separated list using getProperty() as you mentioned
Split that value on comma (I recommend using Guava's Splitter, but String.split or others will work too)
Initialize a new HashMap<String, Integer> and an int index = 0
Iterate through the split tokens, map the current token to index and increment index
Note the implicit assumption that none of the table names have a comma in it.
public class MyComparable implements Comparator<Table>{
#Override
public int compare(Table table1, Table table2) {
return (table1.getTableName().compareTo(table2.getTableName());
}
}
make sure that you have overridden the hashcode and equals in Table class to achieve this.
I wrote you a very simple example on how to work with a Comparator. If you create a class called Main, copy paste below contents in it, compile and run it, you can see what's going on.
A comparator just needs to implement an interface. For this it needs to implement one method (public int compare(T arg0, T arg1). There you specify how a collection will get sorted; in this case according to the alfabet.
I hope this helps you.
import java.util.*;
public class Main {
public static void main(String[] args) {
System.out.println("Start\n");
List<Item> items = new ArrayList<Item>();
for(String s : new String[]{"mzeaez", "xcxv", "hjkhk", "azasq", "iopiop"}) {
items.add(createItem(s));
}
System.out.println("Items before sort:");
System.out.println(Item.toString(items));
Collections.sort(items, new ItemComparator());
System.out.println("Items after sort:");
System.out.println(Item.toString(items));
System.out.println("End");
}
private static Item createItem(String s) {
Item item = new Item();
item.setS(s);
return item;
}
}
class Item {
private String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
#Override
public String toString() {
return "Item: " + s;
}
public static String toString(Collection<Item> items) {
String s = "";
for(Item item : items) {
s += item + "\n";
}
return s;
}
}
class ItemComparator implements Comparator<Item> {
#Override
public int compare(Item item1, Item item2) {
return item1.getS().compareTo(item2.getS());
}
}

How would I iterate through a list of [[tokens]] and replace them with textbox input?

Here is the basic code i'm trying to make work:
Field fields[] = SalesLetter.class.getDeclaredFields();
String fieldName;
for (int j = 0, m = fields.length; j < m; j++) {
fieldName = fields[j].getName(); //example fieldname [[headline]]
templateHTML = templateHTML.replace(fieldName, Letter.fieldName());
}
I believe I'm going about it wrong by trying to getDeclaredFields (which isn't even syntactically correct). When I finished my title, it came up with a few other stackoverflow questions which I read before writing this. They were:
Best way to replace tokens in a large text template
Replacing tokens in a string from an array
It gave me the idea of reading all legal [[tokens]] from a text file, putting them into a hash (err I mean map, this is java :D), then creating an object reference with the same name as that token.
I can't figure out how I would do such a thing in java specifically, or if that would work. Please assist.
Thanks in advance,
Cody Goodman
Note: I'm trying to make everything as flexible as possible, so maybe in the future I could add things such as "[[tokenname]]:this is token name, you need to really think about what the customer wants to come up with a good token name" in a text file, then those fields are generated on my form, and everything works :)
In order to read values from non-static fields of a type, you'll need a reference to an instance of the type:
public class ReflectFields {
static class Letter {
public int baz = 100;
}
static class SalesLetter extends Letter {
public String foo = "bar";
}
public static void main(String[] args) throws Exception {
// TODO: better exception handling, etc.
SalesLetter instance = new SalesLetter();
for (Field field : instance.getClass().getFields()) {
System.out.format("%s = %s%n", field.getName(), field.get(instance));
}
}
}
You'll also have to watch for private fields, etc. In general, this approach should be avoided as it breaks encapsulation by looking at class internals.
Consider using the JavaBean API.
public class BeanHelper {
private final Object bean;
private final Map<String, Method> getters = new TreeMap<String, Method>();
public BeanHelper(Object bean) {
this.bean = bean;
for (PropertyDescriptor pd : Introspector.getBeanInfo(bean.getClass(),
Object.class).getPropertyDescriptors()) {
getters.put(pd.getName(), pd.getReadMethod());
}
}
public Set<String> getProperties() { return getters.keySet(); }
public Object get(String propertyName) {
return getters.get(propertyName).invoke(bean);
}
public static void main(String[] args) {
BeanHelper helper = new BeanHelper(new MyBean());
for (String prop : helper.getProperties()) {
System.out.format("%s = %s%n", prop, helper.get(prop));
}
}
public static class MyBean {
private final String foo = "bar";
private final boolean baz = true;
public String getFoo() { return foo; }
public boolean isBaz() { return baz; }
}
}
Exception handling has been omitted for brevity, so you'll need to add some try/catch blocks (I suggest wrapping the caught exceptions in IllegalStateExceptions).
What about using a template engine like Freemarker, Velocity or StringTemplate:
replace [[ by ${ and ]] by }
create a model from a properties file containing the replacements
process templateHTML
Here an example with Freemarker (without Exception handling)
Configuration config = new Configuration();
StringTemplateLoader loader = new StringTemplateLoader();
config.setTeplateLoader(loader);
Map model = Properites.load(new FileInputStream("tokens.properties"));
loader.putTemplate("html.ftl", templateHTML);
Template template = config.getTemplate("html.ftl");
Writer out = new StringWriter();
template.process(root, out);
String result = out.toString();
StringTemplate may be more simple (replace [[ and ]] by $), but I am not fimilar with it:
Map model = Properites.load(new FileInputStream("tokens.properties"));
StringTemplate template = new StringTemplate(templateHTML);
template.setAttributes(model);
String result = template.toString();
The tokens.properties file looks like:
tokenname:this is token name

Categories