Run multiple tests with Selenium DataProvider - java

I am currently using testng + selenium to automate my tests, and I have the following scenario:
I need to read from an excel file, transform each row in an object and run 1 test for each of them. I am trying to use annotation #DataProvider to return an Array of objects, however it is only able to return Iterators and Objects[][]. Is there any workaround I can use to return an array of Cliente objects from the DataProvider? I have tried the following code, however it only prints the data from Client2:
public class TestDataProvider
{
Cliente cliente;
#DataProvider(name = "test1")
public static Object[][] dataMethod() {
return new Object[][] { { new Cliente("Client1", "1111111111") },
{ new Cliente("Client2", "2222222222") }};
}
#Test(dataProvider = "test1")
public void testMethod(Cliente cliente) {
System.out.println(cliente.getNome() + " " + cliente.getCartao());
}
}
Edit1: Cliente class:
public class Cliente {
private static String name;
private static String card;
//Construtor method
public Cliente(String name, String card){
setname(name);
setCartao(card);
}
public String getName() {
return name;
}
public void setName(String name) {
Cliente.name = name;
}
public String getCard() {
return card;
}
public void setCard(String card) {
Cliente.card = card;
}
}
Values that are printed in the console:
Client2 2222222222
Client2 2222222222

So...
Your prerequisites:
excel file, each row - one dataset
run test for each dataset
What can you do:
Create #DataProvider which return Iterator<Object[]> with your datasets where each Object[] is your row from excel. (the easiest one)
Use #Factory to manually iterate through your datasets and call test methods.
Use #DataProvider to provide data for #Factory and do as above.
The 2nd and 3rd options are complicated, but have some benefits if you has other parameters, except datasets, to run tests.

thanks for the help. With RocketRacoon's third suggestion I managed to resolve my problem. Below is a simple example:
public class ProvidedTest
{
private static nome;
private static cpf;
private static cartao;
#DataProvider
public static Object[][] dataProviderMethod() {
return new Object[][] { {"Client1", "111111111", "444444444"},
{"Client2", "222222222", "555555555"},
{"Client3", "333333333", "666666666"}};
}
#Factory (dataProvider="dataProviderMethod")
public ProvidedTest(String nome, String cpf, String cartao){
this.nome = nome;
this.cpf = cpf;
this.cartao = cartao;
}
#Test
public void testCase(){
System.out.println(cliente.getNome());
System.out.println(cliente.getCpf());
System.out.println(cliente.getCartao());
}
}

Related

ParametrizedTest with displayName and Argument

I am trying to migrate from JUnit4 to JUnit5 and also I'm new to ParametrizedTest in Junit5 and I have a scenario wherein I would like to provide different DisplayName and the Test argument(Object).
Here's the data source I would like to use as an input for #MethodSource("data")
public static Collection<Object[]> data() throws IOException {
List<Object[]> testCaseData = new ArrayList<>();
TestCaseReader testCaseReader = new TestCaseReader(TESTCASE_CSV_RESOURCE);
List<MyClass> testCaseList = testCaseReader.readTestCases();
for (MyClass testCase : testCaseList) {
if (testCase.isActive()) {
Object[] testParameter = new Object[2];
testParameter[0] = String.format("%03d: %s", testCase.getStartingLineNumber(), testCase.getName());
testParameter[1] = testCase;
testCaseData.add(testParameter);
}
}
return testCaseData;
}
And this is the Test
#ParameterizedTest(name = "Scenario: {0}, testCase={1}")
#MethodSource("data")
public void process(MyClass testCase) {
//...
//some operating on testCase methods/variables
}
When executing TestCase, I see the DisplayName is picked up correctly, but the other arguments is not resolvable it says
org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [com.sample.MyClass testCase] in method [public void.MultipleTestCase.process(com.sample.MyClass testCase)]
Could you please guide me what I have done wrong here!
Thanks
Providing test data as Collection<Object[]> is no longer the appropriate way in JUnit 5. You can use a Stream instead. If you need to provide multiple parameters for your test you can use Arguments to wrap them. They are automatically unwrapped upon test execution. The example below gives a general idea on how to do that. You can replace TestCase with MyClass and insert your TestCaseReader code in data.
public class ParameterizedTest {
static Stream<Arguments> data() {
// TODO: Add your TestCaseReader usage to create MyClass / TestCase instances.
List<TestCase> testCases =
List.of(new TestCase("test01", "data01"), new TestCase("test02", "data02"));
return testCases.stream().map(test -> Arguments.arguments(test.getName(), test));
}
#org.junit.jupiter.params.ParameterizedTest(name = "Scenario: {0}, testCase={1}")
#MethodSource("data")
public void process(String name, TestCase testCase) {
System.out.println(name + ": " + testCase.getData());
// TODO: Work with your test case.
}
private static final class TestCase {
private final String name;
private final String data;
public TestCase(String name, String data) {
this.name = name;
this.data = data;
}
public String getName() {
return name;
}
public String getData() {
return data;
}
}
}

Object creation optimisation

I have a below piece of code :
Test class is a POJO of (id and name)
Test test=new Test();
Test test1=new Test();
Test test2=new Test();
for(Asset a : assets)
{
assetId=getAssetId();
test.set(assetId);
test1.set(assetId);
test2.set(assetId);
for(some loop)
{
test.set(assetName);
test1.set(assetName1);
test2.set(assetName2);
setMethod(test);
setMethod1(test1);
setMethod2(test2);
}
}
as we can see there's too much repetitive code. can anyone please help to optimise it?
You can refactor your code introducing new methods helping readability and manuteneability of the code.
First define a method to generate a List of Test
private List<Test> createTests(int size) {
List<Test> tests = new ArrayList();
for (int i = 0; i < size; i++) {
tests.add(new Test());
}
return tests;
}
Add a method to set the assetId on each test of a list.
private void setAssetId(List<Test> tests, String assetId) {
for (Test test: tests) {
test.set(assetId);
}
}
Than you can refactoring the first part of code as
List<Test> tests = createTests(3);
for (Asset asset: assets) {
setAssetId(tests, asset.getAssetId());
...
}
The inner loop is not clear (it is more a pseudo code, then java code), but the idea is the same.
If you see some duplication in your code extract a method and refactor the original code calling that method. The whole code will be a lot more readable and if repetitions are many can be also smaller.
With Lambda you can save more code.
Replace the syso with your stuff to do.
package main.java.stackoverflow.oopTest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class Test {
private int id;
private String name;
public Test(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Test(int id) {
this(id, "");
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public static void main(String[] args) {
List<Test> listOfTest = new ArrayList<>();
// create your POJOS
IntStream.range(0, 3).forEach(index -> {
listOfTest.add(new Test(index));
});
//iterate over your POJOS
listOfTest.forEach(t -> System.out.println(t.id));
}
}

How to Insert ArrayList data to the DataBase

Im try to insert data into Database using ArrayList.there is a Erro msg.
That is my Custmer.class method. this is what i got from when i going to pass ArrayList into another class.
incompatible types: ArrayList<String> cannot be converted to ArrayList<Inquiries>
I want to know how to do this using correct Using OOP concept
public void passingMsg(ArrayList<Inquiries> arrlist){
try {
System.out.println("Method "+arrlist);
String sq = "INSERT INTO Inquiries (name,mail,tp,msg)VALUES(?,?,?)";
PreparedStatement pr = con.prepareStatement(sq);
for(int i=0;i<arrlist.size();i++){
pr.setString(1,arrlist.get(i).getName());
pr.setString(2,arrlist.get(i).getMail());
pr.setString(3,arrlist.get(i).getTp());
pr.setString(4,arrlist.get(i).getMsg());
}
pr.executeQuery();//executeBatch();
} catch (SQLException ex) {
}
}
and this is how i get values from user
String name = txtName.getText();
String mail = txtEmail.getText();
String tp = txtTp.getText();
String msg = txtMsg.getText();
ArrayList<String> arrInq = new ArrayList<String>();
arrInq.add(name);
arrInq.add(mail);
arrInq.add(tp);
arrInq.add(msg);
Custmer c =new Custmer();
if( c.passingMsg(arrInq)){
try {
JOptionPane.showMessageDialog(this, "Successs!!");
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Unsuccesss!!");
e.printStackTrace();
}
}
and this is my Inquiries.class :
public class Inquiries {
private String name;
private String mail;
private String tp;
private String msg;
public Inquiries(String name,String mail,String tp,String msg){
this.name = name;
this.mail = mail;
this.tp = tp;
this.msg = msg;
}
//
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getTp() {
return tp;
}
public void setTp(String tp) {
this.tp = tp;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
Can Some one please explain whats wrong with this. please ?
Reason For Error
This was simply telling you that your types were incompatible for the operation you were trying to perform. In your passingMsg() method, you have its header as: public void passingMsg(ArrayList<Inquiries> arrlist). However, inside your "how i get values from user" area, which I will now refer to as "2nd Snippet", you have your method call declared as: if( c.passingMsg(arrInq)). This means that you are implying that your parameter being passed, arrInq in this case, is of the type ArrayList<Inquiries>, but it's not. It's being initialized in your 2nd Snippet as: ArrayList<String> arrInq = new ArrayList<String>();
Simple Fix
I take no responsibility for this code; use at your own risk. To fix this, you would want to change that entire 2nd Snippet to something similar to the following:
String name = txtName.getText();
String mail = txtEmail.getText();
String tp = txtTp.getText();
String msg = txtMsg.getText();
ArrayList<Inquiries> arrInq = new ArrayList<Inquiries>();
arrInq.add(new Inquiries(name, mail, tp, msg));
Custmer c = new Custmer();
try {
c.passingMsg(arrInq);
JOptionPane.showMessageDialog(this, "Successs!!");
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Unsuccesss!!");
e.printStackTrace();
}
You would also want to change the method header to either return a boolean, or fix it up a little bit to actually throw the exception. Such as:
public void passingMsg(ArrayList<Inquiries> arrlist) {
System.out.println("Method " + arrlist);
String sq = "INSERT INTO Inquiries(name,mail,tp,msg) VALUES(?,?,?)";
PreparedStatement pr = con.prepareStatement(sq);
for (Inquiries inquiries : arrlist) {
pr.setString(1, inquiries.getName());
pr.setString(2, inquiries.getMail());
pr.setString(3, inquiries.getTp());
pr.setString(4, inquiries.getMsg());
}
pr.executeQuery();//executeBatch();
}
Let's talk in O-O-P way.
Here Inquiries is your model, model is nothing but simple class that has instance members and public methods to get and set value of model's instance variable.
Generally we put all database related operations code in their respective models.
e.g. I have model "Model" which typically maps to database table say it as "TableModel" ,I would do something like this:
public class Model{
private int id;
private String attr;
//other properties of the model
public int getId(){
return id;
}
public void setId(int id){
this.id=id;
}
//other getters and setters
//here we write methods to performs database operations
public void save(){
//use "this" to get properties of object
//logic to save to this object in database table TableModel as record
}
public void delete(int id){
//logic to delete this object i.e. from database table TableModel
}
public Model get(int id){
//retrieve record from table TableModel with this id
}
//other methods to get data from database.
}
Now question is how I can use this in some another class. Let's say I have list of Model objects and I wish to insert them in to database.I will do it something like this:
public class AnotherClass{
public void someMethod(){
//create list of models objects e.g. get them from user interface
ArrayList<Model> models=new ArrayList<>();
for(int i=0;i<3;i++){
Model model=new Model();
model.setId(i);
model.setAttr("attr"+i);
models.add(model);
}
SomeOtherClass obj=new SomeOtherClass();
obj.insert(models);
}
}
public class SomeOtherClass{
//other code above.....
//my method that inserts each Model object in database
//Note: this is sample method , you should do it in optimized way
// e.g. batch insert
public void insert(ArrayList<Model> models){
for(Model myModel:models){
myModel.save();
}
}
//other code below.....
}
You are using the wrong type parameter for the ArrayList. Instead of ArrayList<String> you need ArrayList<Inquiries>. To fix the problem, you should remove this code ...
ArrayList<String> arrInq = new ArrayList<String>();
arrInq.add(name);
arrInq.add(mail);
arrInq.add(tp);
arrInq.add(msg);
... and replace it with this code:
ArrayList<Inquiries> arrInq = new ArrayList<Inquiries>();
arrInq.add(new Inquiries(name, mail, tp, msg));

Map selected fields from multiple POJOs to create one POJO

I have a couple of objects from which selected members should be combined to create an output object. All these are POJOs. I am seeing that all object mappers work on a single POJO to another POJO level. Is there any mapper that supports what I am looking for? Of course, I understand that there is some mapping stuff that I need to specify.
Edit:
I know how to get this done by writings own Java class. I am just looking for a way to do it with one of the mapping libraries.
You aren't limited in what you require to be passed to your mapper. You can define it to accept several items and build the object based on the multiple inputs. Here is an example:
public class ClassOne {
private final String someProperty;
public ClassOne(String someProperty) {
this.someProperty = someProperty;
}
public String getSomeProperty() {
return someProperty;
}
}
public class ClassTwo {
private final String someOtherProperty;
public ClassTwo(String someOtherProperty) {
this.someOtherProperty = someOtherProperty;
}
public String getSomeOtherProperty() {
return someOtherProperty;
}
}
public class CombinedClass {
public static CombinedClass mapper(ClassOne one, ClassTwo two){
return new CombinedClass(one.getSomeProperty(), two.getSomeOtherProperty());
}
private final String someProperty;
private final String someOtherProperty;
private CombinedClass(String someProperty, String someOtherProperty) {
this.someProperty = someProperty;
this.someOtherProperty = someOtherProperty;
}
public String getSomeProperty() {
return someProperty;
}
public String getSomeOtherProperty() {
return someOtherProperty;
}
}

Make JsonGetter case insensitive

I'm using JacksonAnnotation along with Spring Framework to parse a JSON that I get from a web service for my app.
I have the same data structure coming from two distinct methods but there is a field in one of them that comes capitalized. I don't want to create two data structures just because of that.
Is there any way that I make JsonGetter case insensitive or at least make it accept two version of a string?
Currently I have to use this for method A
#JsonGetter("CEP")
public String getCEP() {
return this.cep;
}
and this for method B
#JsonGetter("Cep")
public String getCEP() {
return this.cep;
}
Thanks
You can create new setter method for each possibility of property name:
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue("{\"Cep\":\"value\"}", Entity.class));
System.out.println(mapper.readValue("{\"CEP\":\"value\"}", Entity.class));
}
}
class Entity {
private String cep;
public String getCep() {
return cep;
}
#JsonSetter("Cep")
public void setCep(String cep) {
this.cep = cep;
}
#JsonSetter("CEP")
public void setCepCapitalized(String cep) {
this.cep = cep;
}
#Override
public String toString() {
return "Entity [cep=" + cep + "]";
}
}

Categories

Resources