About Me

My Photo
A Sun certified Java professional with time proven experience in architecture and designing of mid/large scale Java/JEE based applications. Creator of the EasyTest Framework.A lot of experience with technologies such as Spring framework, Hibernate , JPA, Java4-6, REST, SOA , YUI , JUnit , Cloud Foundry PaaS and other technologies.

Monday, August 27, 2012

EasyTest(ing) in Java : A Data Driven Testing Framework is finally here


Click Here to directly go to EasyTest documentation

EasyTest is an Open Source Data Driven Testing Framework supporting JUnit



I have talked a lot about JUnit and its support(or lack of) for Data Driven Testing in my previous blog posts. Thanks to the community, I have received a lot of positive feedback on my blogs and a lot of people agreeing to the fact that although JUnit is an excellent tool for writing test cases, it has somehow not given its users enough to write clean Data Driven Tests.

Let's revise one more time what JUnit provides its users to perform some sort of Data Driven Testing:
1) Parameterized Runner, that has its own syntax and annotations.
2) Theories Runner, again which has its own syntax.

Both have their drawbacks and are listed here: Parameterized Runner and its drawbacks and Theories Runner and Its drawbacks.

EasyTest tries to bridge the gap between JUnit and its support(or lack of) for Data Driven Testing.

Lets first briefly look at what is EasyTest project.

EasyTest 

EasyTest is an open source community driven extension to JUnit that provides a lot of features that JUnit is not able to. EasyTest code base lies here : EasyTest source code

Here are some of the highlights of EasyTest:
  1. EasyTest supports passing method parameters to the methods annotated with JUnit's @Test annotation. (Isn't that what we always wanted in the first place.)
  2. EasyTest supports passing input test data(in different formats like CSV, Excel, XML or Custom Loaders) to the Test class using annotations (for eg. @DataLoader)
  3. EasyTest supports passing input test data(in different formats like CSV, Excel, XML or Custom Loaders) to the Test method as well using annotations (@DataLoader). 
  4. EasyTest has inbuilt support for Java PropertyEditors. This means that a user can reuse the classes to get concrete user defined objects as part of the test parameters. In case of standard primitive types(like int , long, String etc) you don't even have to register any property editors as they are supported by default. 
  5. EasyTest also supports custom converters, in cases where PropertyEditor support is not enough.
  6. EasyTest supports custom loaders for parsing user defined input test data file in case our existing data loader support is not enough. So a user can provide its input test data in, lets say JSON format and then write its own loader to load the test data. This gives a lot of flexibility to the end users.
  7. EasyTest also supports returning output data from the test method and capturing it in the same file from which the input was provided.
  8. EasyTest supports a mechanism where you can intercept calls to your class under test and do things before or after the method has been tested. This is extremely useful in cases where for example you want to measure the time taken by your test method. EasyTest supports it by default and if you enable @Intercept annotation then it will write the performance measurements in a log file. Obviously, you can provide your own custom implementation of the interceptor and use that instead of the one provided by EasyTest.
  9. EasyTest supports generating test reports (using Jasper behind the scenes) for your test classes. Reports can be generated in PDF or other formats and can be put at any place in your file system.
  10. EasyTest supports Spring Integration Testing. Now you can write Data Driven Integration tests using EasyTest's support classes for Spring.

And there are a lot of new features. You can find what EasyTest currently supports here as well as on the WIKI page of EasyTest.

How to start with EasyTest

In order to get up and running with EasyTest all you have to do is download the latest JAR from Maven. Just include the latest dependency in your POM file as described here. At the time of writing this post, the latest version was 1.1:

<dependency>
    <groupId>org.easetech</groupId>
    <artifactId>easytest-core</artifactId>
    <version>1.1</version>
</dependency>

Once you have it in your class path, simply run your test cases with EasyTestRunner like this:
@RunWith(DataDrivenTestRunner.class)

We have looked at what EasyTest is and what it supports. So lets see some real action.

Use Case 1: User says : "I want to provide my test input data to all my 15 test method in my test Class using a single CSV file"

Realization of Use Case :
@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths = { "myInputTestDataForMyClass.csv" })
public class TestMyClass {

@Test
public void testGetItems(@Param()
Map inputData) {
    // Map is the easiest of input Parameters that can be used within the test method. This map actually contains the key value pair of the test data that the method requires. In case of CSV files, the input Map parameter represents a single row of test data.

}
Explanation: As you can see, we are using JUnit's standard approach to specify the test runner. In our case it is the DataDrivenTestRunner.
Next thing to notice is @DataLoader annotation. This annotation tells the EasyTest framework the list of files that contains the input test data. EasyTest will try to read all the files, collect the data in its usable format(which is a Map) and then provide the correct list of data to the test methods.

Another thing to notice is that we are using @Test annotation on the test method. This is the JUnit annotation to run the test. EasyTest supports passing parameters to the methods that are annotated with @Test annotation.

Finally, the test method has a parameter named inputData which is of Type Map and has annotation @param. The annotation @param tells the EasyTest framework that this test method requires a parameter. Map is the easiest of input parameters that can be used withing the test method. This map actually contains the key value pair of the test data that the method requires. In case of CSV files, the input Map parameter represents a single row of test data.

Use Case 2: User says:"The above is fine but I want to pass some specific test data to test method 3 and rest of the test methods can take input data specified at the class level."

Realization of Use Case:

@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths = { "getItemsData.csv" })
public class TestMyClass {

@Test
@DataLoader(filePaths = { "getCustomData.csv" }, loaderType = LoaderType.CSV)
public void testGetItems(@Param()
Map inputData) {
    ..........

}                                                                                         @Test                                                                                     public void testGetInputdatafromClassLevelCSVFile(Map inputData){             ..                                                                                     }

Explanation: In the above case, "testGetInputdatafromClassLevelCSVFile" method will take its test input from the getItemsData.csv whereas testGetItems method will take data from getCustomData.csv

Use Case 3: user says: "I want to use my custom object instead of a Map as method parameters."

Realization of Use Case:

@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths = { "getItemsData.csv" })
public class TestMyClass {
@BeforeClass
    public static void setUp(){
        PropertyEditorManager.registerEditor(LibraryId.class, LibraryIdEditor.class);
    }
@Test
public void testGetItems(@Param()
LibraryId id) {
   ...

}

Explanation: A user can use his custom objects as input parameters to the test method. In the above case both a user has used LibraryId and has specified that it is an object that supports RegistryEditors. EasyTest framework will then automatically search for the editors and convert the String data as received from CSV file into LibraryId object and pass it to the test method.

Use Case 4: User says:" Registry Editor is fine, but what if I want to pass my custom object that is not an Editor.

Realization of Use Case:

@RunWith(DataDrivenTestRunner.class)
@DataLoader(filePaths = { "getItemsData.xls" } , loaderType = LoaderType.EXCEL)
public class TestMyClass {
@BeforeClass
    public static void setUp(){
        ConverterManager.registerConverter(LibraryInformationConverter.class);
    }
@Test
public void testGetItems(@Param() LibraryInformation libInfo) {
   LibraryId libId = libInfo.getLibraryId(); //and so on
   
}

Explanation: A user can use a ConverterManager class to specify his own test converter that can convert the data from a Map to a custom object. Calling of the converter at the right time, providing the right object to the test method is all taken care of by the EasyTest framework.

Use Case 5:User says: "We dont use either CSV, Excel or XML representation of our test data. Instead we use YML to specify test data and we dont want to move to any other specification."

Realization of Use Case:

@RunWith(EasyTestRunner.class)
@DataLoader(filePaths = { "getItemsData.xml" }, loaderType=LoaderType.XML)
public class TestMyClass {


@Test
@DataLoader(filePaths = { "getCustomData.yml" }, loaderType = FileType.CUSTOM , loader = MyYMLDataLoader.class)public void testGetItems(@Param()LibraryInfo libInfo) {...}

Explanation: EasyTest supports CustomDataLoaders for specifying test data in format that is currently not supported by EasyTest. In the above case, the user has to specify the fileType = loaderType.CUSTOM and use the loader attribute to specify its own data loader.

EasyTest is an open source Framework developed using JUnits classes and APIs. It is a community project and looks at the community to provide feedback on how they find the current framework and what they expect to see in the near future. We have our milestones for every month and those milestones are decided by the community. 

If you have any specific requirements, do leave a message or issue on the EasyTest source control here : EasyTest Issues/feature requirements

You can explore EasyTest and its source code here : EasyTest source code
You can also explore the EasyTest's "Getting Started" guide here : EasyTest Introduction and Getting Started

Conclusion

EasyTest is a framework developed to complement current JUnit's support and not to replace it. 

EasyTest aims to simplify the life of the developer who gets almost no time to write test cases for the functionality that took him days to implement. Its a developer friendly framework to writing JUnit based Data Driven Test Cases easily,effectively and quickly.
SideNote: JUnit backed framework implies a framework that has been developed using JUnit classes and API.

3 comments:

Rajesh said...

Hi,

I am running into an issue -
I am using and Excel file in the data logger. Now, I am getting the error below - "Data does not exist for the specified method with name". I have made sure that the method name is present in cell (1,1) of the excel spreadsheet. The path is also correct.
Could you please help me with this issue - I need to have this resolved urgently. Thanks.

Rajesh said...

Got rid of the error by using the latest version. Thanks!

Anuj said...

Hi Rajesh,
Sorry I couldnt reply on time. And I am glad you have the problem solved. In case you encounter any more issues, you can directly mail me at anujkumar@easetech.org or you can also open an issue on the easytest Github page her : https://github.com/EaseTech/easytest-core/issues?state=open