-
Notifications
You must be signed in to change notification settings - Fork 21
Understanding @DataLoader annotation
EasyTest provides its users with the facility to do Data Driven Testing in Java and uses JUnit classes behind the scene to achieve its objective. One major annotation in EasyTest is the DataLoader annotation. This is a class/method level annotation that can be used to tell the EasyTest framework how and from where to load the test data. This page describes this annotation in detail and explains with code samples how each of its attributes can be used.
Following is the list of attributes of the Dataloader annotation:
- filePaths – This attribute specifies list of files representing the input test data for the given test method.
- loaderType - The type of file that contains the data.
- Loader - The custom Loader class that will be used by EasyTest to load the test data
- writeData - Boolean identifying whether the data should be written back to the file or not. Default behavior is that the data will be written back to the file.
- appendData - Boolean identifying whether data specified in two different files for the same method should be appended or replaced. Default behavior is to replace the data present in one file from the other.
The subsequent sections explain each attribute in detail.
filePaths(JavaDoc)
Attribute Description
Filepaths attribute specifies the list of files containing the input test data for the given test method. Multiple files may be specified here. Note that currently EasyTest supports files of type CSV, EXCEL and XML. If users wish to load data from some other filetype, they can do so by specifying a custom loader. More details about this are specified in the description of the loader attribute below.
Attribute Input
This attribute accepts a String[] i.e. a String array of file paths. The path can be either a classpath, url path or a local directory path. The user can also specify a variable representing the path using the EL syntax : ${my.file.path} and then provide the actual value of the path at runtime using System Properties(for eg. from command line using -D option like -Dmy.file.path=/Users/kacy/testdata.csv)
Default value
Default value is an empty array.
The following is a code listing which demonstrates how this attribute may be used:
package easytech.demo;
import org.easetech.easytest.annotation.DataLoader;
import org.easetech.easytest.annotation.Param;
import org.easetech.easytest.runner.DataDrivenTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths={"testData.csv"})
public class DataLoadderFilePathsDemo{
@Test
public void simplTestMethod(@Param(name="name")String name , @Param(name="age")int age){
}
}
Code Description
- The DataLoadderFilePathsDemo class is annotated with the DataLoader annotation. The filePaths attribute is used with a value of “testData.csv”. This indicates that the input data for testing should be used from this file. In this example a csv file is used, but an excel/xml file may also be used.
- A method called simpleTestMethod is defined. This is the actual test method that needs to be invoked with different data sets. It accepts 2 parameters called name , age. The values for these parameters will be obtained from the input CSV file.
Input CSV file
The following is the input CSV file used in this example:
simplTestMethod,name,age
,Ravi,32
,Christiaan,29
,Anuj,31
The first column specifies the name of the method for which the test data is required, in this case "simpleTestMethod". Next in the same column, the input parameter names that are used in the test method are defined. In this case the parameters are : name , age. All these are comma separated as required for a CSV file. The subsequent records define the actual data associated with the test method and for each parameter.
Output
When this code is run, the test method i.e. simpleTestMethod will be executed as many times as there are records in the input file. So in this case since there are 3 records in the input file, the test will be run 3 times.
loaderType(JavaDoc)
Attribute Description
LoaderType attribute specifies the type of loader that will be used to load the input test data. This attribute is not really required as EasyTest can look up the file extension to figure out the file type. LoaderType is present merely to give hint to EasyTest. It is also used to specify that the loader is Custom and not a standard loader. Everytime a user uses his own format or mechanism to load the test data, he should specify the value of LoaderType as CUSTOM.
Attribute Input
The input to this attribute is an enum constant of type LoaderType
So briefly, this attribute can have the following values:
- LoaderType.CSV - Identifies that the type of test data file is a framework based CSV file and CSVDataLoader will be used to load the test data.
- LoaderType.CUSTOM - Identifies that the test data will be loaded using the user defined custom loader.
- LoaderType.EXCEL - Identifies that the type of test data file is a framework based EXCEL file and ExcelDataLoader will be used to load the test data.
- LoaderType.NONE - Identifies that the user has not specified any specific loader type. This is also the default value.
- LoaderType.XML - Identifies that the type of test data file is a framework based XML file and XMLDataLoader will be used to load the test data.
Default value
The default value for this attribute is LoaderType.NONE Note that this is an optional attribute, so NONE indicates that the user has not specified any CUSTOM loader type and one of the internal Data Loaders will be used to load the test data.
package easytech.demo;
import org.easetech.easytest.annotation.DataLoader;
import org.easetech.easytest.annotation.Param;
import org.easetech.easytest.loader.LoaderType;
import org.easetech.easytest.runner.DataDrivenTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths={"testData.csv"},loaderType=LoaderType.CSV)
public class DataLoaderLoaderTypeDemo{
@Test
public void simplTestMethod(@Param(name="name")String name , @Param(name="age")int age){
}
}
Code Description
- The DataLoaderLoaderTypeDemo class is annotated with the DataLoader annotation.
- The filePaths attribute is used to specify the path of the input CSV file.
- The loaderType attribute is specified with value as LoaderType.CSV. This indicates that the input file is a csv file.
- A method called simpleTestMethod is defined. This is the actual test method that needs to be invoked with different data sets. It accepts 2 parameters called name , age which will be obtained from the input CSV file.
Input CSV file
The following is the input CSV file used in this example:
simplTestMethod,name,age
,Ravi,32
,Christiaan,29
,Anuj,31
The first column specifies the name of the method for which the test data is required, in this case "simpleTestMethod". Next in the same column, the input parameter names that are used in the test method are defined. In this case the parameters are : name , age. All these are comma separated as required for a CSV file. The subsequent records define the actual data associated with the test method and for each parameter.
Output
When this code is run, the test method i.e. simpleTestMethod will be executed as many times as there are records in the input file. So in this case since there are 3 records in the input file, the test will be run 3 times.
loader(JavaDoc)
Attribute Description
This attribute specifies the custom loader that will be used by EasyTest to load the test data. As mentioned previously, EasyTest currently supports loading data from CSV,XML and Excel files. If you want data to be loaded from some other source, then you can define your own custom loader class and specify the name of the class as the value of this attribute.
Attribute Input
Name of the class that will be used to load the custom data.
Default value
The default value of this attribute is EmptyLoader and is used only when the data cannot be loaded using the internal Loaders and no Custom loader is defined. Note that this attribute is optional. So if not specified, it defaults to EmptyLoader.class
package easytech.demo;
import org.easetech.easytest.annotation.DataLoader;
import org.easetech.easytest.runner.DataDrivenTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DataDrivenTestRunner.class)
public class DataLoaderCustomLoaderDemo{
@Test
@DataLoader(loader = CustomObjectDataLoader.class)
public void testGetItemsWithCustomLoader(Item item){
System.out.println("Item id="+item.getId());
System.out.println("Item name="+item.getName());
}
}
Code Description
- The DataLoaderCustomLoaderDemo is annotated with the loader attribute. It is assigned the name of the class which will load the data for this test.
- The testGetItemsWithCustomLoader method accepts one parameter which is a type of a class called Item.
- The CustomObjectDataLoader class specifies how to read data from the Item class and invoke this test multiple times for all the Item instances specified via the Custom loader.
NOTE that in the above example the DataLoader annotation is specified at the method level instead of class level. A user can override the test data specified at the class level by using the dataloader annotation at the method level. More on it later in the documentation below.
Input
In this case, no external file is used as input. Instead the data is specified in the CustomDataLoader.java class for Item instances as detailed below.
Item class
package easytech.demo;
public class Item {
public Item(int id, String name) {
super();
this.id = id;
this.name = name;
}
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
As can be seen, this is a simple POJO that has 2 fields, id and name. A constructor is used to initialize these fields and getter/setter methods are also present.
CustomObjectLoader class
package easytech.demo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.easetech.easytest.io.Resource;
import org.easetech.easytest.loader.Loader;
/**
*
* A Custom Data Loader that simply provides data from the class itself without reading any external files.
*
*/
public class CustomObjectDataLoader implements Loader {
public Map<String, List<Map<String, Object>>> loadData(Resource resource) {
Map<String, List<Map<String, Object>>> result = new HashMap<String, List<Map<String, Object>>>();
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> map1 = new HashMap<String, Object>();
Map<String, Object> map2 = new HashMap<String, Object>();
Item item1 = new Item (1, "Item1");
Item item2= new Item (1, "Item2");
map1.put("Item", item1);
map2.put("Item", item2);
list.add(map1);
list.add(map2);
result.put("testGetItemsWithCustomLoader", list);
return result;
}
}
Code Explanation
- This class implements the Loaderinterface
- This interface defines 2 methods, loadData and writeData. The loadData is the main method and is described below.
loadData method
-
The loadData method reads data from the Resource instance passed as parameter. In this case, since the data to be read is hardcoded into this method, this parameter is not used.
-
Its return type is a Map in which the key is the methodName for which the data is being loaded and the value is a List. This map is first created.
-
Each element in this list is a Map object. The Map contains the attributeName as key and AttributeValue as value. 2 Map objects are created to store data corresponding to 2 Item instances for which the tests need to be executed.
-
This Map object has key value pairs corresponding to the data being loaded. So in this case 2 Item instances are created with some test data and added to the two Maps.
-
Note that the key value in this map must match the parameter name specified in the test method. If no parameter name is specified, then EasyTest will take the Simple Name of the Class of the parameter and try to match it with the param name passed as test data. So since we are trying to load data of type “Item”, the key to this map should be “Item” since no parameter name is specified in the test method name. If the test method was specified as follows:
public void testGetItemsWithCustomLoader(@Param(name="name")Item item)
Then in this case, they key to this Map needs to be specified as “name”
- The Maps are added to the List and the List is added to the final map which has the method name as the key
Output
When this code is executed, the CustomDataLoader will run the test 2 times, for both the item instances specified.
writeData(JavaDoc)
Attribute Description
This is a Boolean attribute which specifies whether the data returned by a test method should be written back to the input file. It defaults to true indicating that the data should be written back to the file. Note that data will be written back to the file only if the test method returns something. In case the test method returns void, then even though this attribute is set to true, nothing will be written back to the file. In case we do not need the data to be written back to the file, we need to set this flag to false.
Attribute Input
This attribute accepts a boolean value.
Default value
The default value of this attribute is true which indicates that the output of the test method should be written back to the input file.
The following is a code listing which demonstrates how this attribute may be used:
package easytech.demo;
import org.easetech.easytest.annotation.DataLoader;
import org.easetech.easytest.annotation.Param;
import org.easetech.easytest.runner.DataDrivenTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths={"testData.csv"})
public class DataLoaderWriteDataDemo{
@Test
public int simplTestMethod(@Param(name="name")String name , @Param(name="age")int age){
return 5;
}
}
Code Description
-
The DataLoaderWriteDataDemo class is annotated with the DataLoader annotation. The filePaths attribute is used to specify the path of the input CSV file.
-
Note that the writeData attribute is not really specified, since it defaults to true. So by default data will be written back to the input file. If we do not want this data to be written to the input file, we need to set this attribute to false as follows:
@DataLoader(filePaths={"testData.csv"},writeData=false)
-
A method called simpleTestMethod is defined. This is the actual test method that needs to be invoked with different data sets. It accepts 2 parameters called name and age which will be obtained from the input CSV file. It returns an integer value. For demo purpose, this is hard-coded to 5. So this value will be written back to the input CSV file once the test is executed.
Input CSV file
The following is the input CSV file used in this example:
simplTestMethod,name,age
,Ravi,32
,Christiaan,29
,Anuj,31
The first column specifies the name of the method for which the test data is required, in this case "simpleTestMethod". Next in the same column, the input parameter names that are used in the test method are defined. In this case the parameters are : name , age. All these are comma separated as required for a CSV file. The subsequent records define the actual data associated with the test method and for each parameter.
Output
When this code is run, the test method i.e. simpleTestMethod will be executed as many times as there are records in the input file. Also, the input file will be modified as follows:
simplTestMethod,name,age,ActualResult,Duration(ms)
"",Ravi,32,5,1.0
"",Christiaan,29,5,0.0
"",Anuj,31,5,0.0
As can be seen, 2 additional columns are added to the input file:
- Actual result – which has the value returned by the simpleTestMethod
- Duration – This specifies the duration of each run of the simpleTestMethod
appendData(JavaDoc)
Attribute Description
This attribute specifies whether data specified in two different files for the same method should be appended or replaced. If this flag is set to true, then data in the first file will be appended with the data in the second file before the test is run. So the test will be executed for both sets of data. Default value of this flag is false which indicates that data should be replaced. So the data in the first file will be replaced by the data in the 2nd file before the test is run. So the test will be executed only for the data in the 2nd file.
Attribute Input
This attribute accepts a boolean value
Default value
The default value of this attribute is false which indicates that data from the second file should not be appended to the data in the first file. Note that this attribute is optional.
Code Description
package easytech.demo;
import org.easetech.easytest.annotation.DataLoader;
import org.easetech.easytest.annotation.Param;
import org.easetech.easytest.runner.DataDrivenTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths={"testData.csv","testData1.csv"},appendData=true)
public class DataLoaderAppendDataDemo{
@Test
public void simplTestMethod(@Param(name="name")String name , @Param(name="age")int age){
}
}
Code Description
- The DataLoaderFilePathsDemo class is annotated with the DataLoader annotation. The filePaths attribute is used to specify the path of the input CSV files .In this case 2 files are specified, testData.csv and testData1.csv
- The appendData attribute is used and is set to a value of true in order to specify that the data from both the input files should be used.
- A method called simpleTestMethod is defined. This is the actual test method that needs to be invoked with different data sets. It accepts 2 parameters called name and age which will be obtained from the input CSV file. It returns an integer value. For demo purpose, this is hard-coded to 5.
Input CSV file
This example uses 2 CSV files as input.
testData.csv is as follows:
simplTestMethod,name,age
,Ravi,32
,Christiaan,29
,Anuj,31
testData1.csv is as follows:
simplTestMethod,name,age
,Ravi2,32
,Christiaan2,29
,Anuj2,31
Output
Since appendData is set to true, data from both files will be used. So the test will be run 6 times, 3 times for the data in testData.csv file and 3 times for the data in testData1.csv file. Note, in case we do not want data from both files to be used, this attribute can be set to false(or left out as it defaults to false). This will cause the data from testData1.csv file to be written to testData.csv file and then the tests will be executed. So the test will be executed only for the overwritten data in testData.csv.
As mentioned earlier, the DataLoader annotation can be specified at class level as well as method level. When specified at method level, DataLoader annotation will always override the class level DataLoader annotation for that particular test method.
package easytech.demo;
import org.easetech.easytest.annotation.DataLoader;
import org.easetech.easytest.annotation.Param;
import org.easetech.easytest.runner.DataDrivenTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths={"testData.csv"})
public class DataLoaderOverriddingDemo{
@Test
@DataLoader(filePaths={"testData1.csv"})
public void simplTestMethod(@Param(name="name")String name , @Param(name="age")int age){
System.out.println("Name="+name);
}
}
Code Description
- The DataLoaderOverriddingDemo class is annotated with the DataLoader annotation and the filePaths attribute is specified to specify the input file as testData.csv
- A method called simpleTestMethod is defined. This is the actual test method that needs to be invoked with different data sets. It accepts 2 parameters called name , age.
- The test method is also annotated with the DataLoader annotation and the filePaths attribute is specified to specify the input file as testData1.csv
- Since the method level annotation overrides the class level annotation, the file specified with the method level annotation will be used and so the test will be executed for the data specified in testData1.csv
Input
This example uses 2 CSV files as input.
testData.csv is as follows:
simplTestMethod,name,age
,Ravi,32
,Christiaan,29
,Anuj,31
testData1.csv is as follows:
simplTestMethod,name,age
,Ravi2,32
,Christiaan2,29
,Anuj2,31
Output
As mentioned previously, since the method level annotation overrides the class level annotation, the test is executed using the test data in the file specified at the method level i.e. testData1.csv.
Following is the output of running this test:
Name=Ravi2
Name=Christiaan2
Name=Anuj2
For any queries/issues/clarifications please contact [email protected]