Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / ALM

Agile ALM - Data-driven Tests with XStream

4.20/5 (2 votes)
24 Jun 2011CPOL3 min read 10.6K  
A chapter excerpt from Agile ALM
image002.jpgAgile ALM

By Michael Hüttermann

XStream is an XML serializer and deserializer. In this article, based on chapter 8 of Agile ALM, author Michael Hüttermann discusses how XStream can be used when you need an object from an XML structure or vice versa.

You may also be interested in…

XStream is an XML serializer and deserializer. It can be used for various situations where you need an object from an XML structure or vice versa. It is easy to use and the XML is very clean.

If you are defining test data of flat objects in Java, you need to write some glue code. If you need to define object trees, you will soon realize that Java is the wrong language and that it is very time consuming to initialize every child object, set the values, and assign them to the parent object. This could be fine if you need it at a few points of you application, but if there are object hierarchies that are predefined, you should extract them. An XML structure is one way we could describe object hierarchies. In fact, it is a very common approach because there are a lot of tools available and you don’t need to worry about using the wrong character sets.

Let’s try with a simple example. First, add the XStream dependency to your pom.xml:

<dependency> 
  <groupId>com.thoughtworks.xstream</groupId> 
  <artifactId>xstream</artifactId> 
  <version>1.3.1</version> 
</dependency>

Now, let’s write a simple Java bean:

C#
public class User { 
    private String firstName; 
    private String lastName; 
    public User(String firstName, String lastName) { 
        this.lastName = lastName; 
        this.firstName = firstName; 
    } 
    ... 
}

To serialize User with XStream, we can use XStream’s API as follows:

C#
XStream xstream = new XStream(); 
User user = new User("Paul", "Breitner"); 
String xml = xstream.toXML(user);

Depending on the package name you use in your Java class, the result is similar to this: 

<org.agile.alm.entities.User> 
  <firstName>Paul</firstName> 
  <lastName>Breitner</lastName> 
</org.agile.alm.entities.User>

As you can see, there are some package definitions in the XML file. If you want a cleaner XML structure, you can define so-called aliases in XStream. You can define an alias either as an annotation or as a special definition. If you can control your objects, then annotations are a very handy way to write and forget about the aliases, especially if you use that object multiple times on different code positions. Serializing with a defined alias looks like this:

C#
XStream xstream = new XStream(); 
xstream.alias("user",User.class); 
User user = new User("Paul", "Breitner"); 
String xml = xstream.toXML(user);

Working with XStream annotations looks as follows:

C#
import com.thoughtworks.xstream.annotations.XStreamAlias; 

@XStreamAlias("user") 
public class User { 
    private String firstName; 
    private String lastName; 
    ... 
}

In the Java code, serializing based on annotations looks like this:

Java
XStream xstream = new XStream(); 
xstream.processAnnotations(User.class); 
User user = new User("Paul", "Breitner"); 
String xml = xstream.toXML(user);

For deserializing objects from XML, you must go the following way:

<user> 
  <firstName>Paul</firstName> 
  <lastName>Breitner</lastName> 
</user>

It becomes even more helpful if you have larger object trees for deserialization. Normally, the objects of your model are already defined. With XStream, you can reuse complex objects to drive your dataProvider in TestNG.

Now let’s go back to TestNG. To use your list of objects as a dataProvider, you can use a helper function that transforms it into an array of arrays, as seen in listing 1.

Listing 1 TestNG test class reading data from XML via XStream

C#
import org.agile.alm.entities.User;
import com.thoughtworks.xstream.XStream;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
 
public class TestMe {
   …
   protected <T> List<T> readListData(String filename) {   #A
      return (List<T>) xstream.fromXML(this.getClass().getClassLoader().
                  getResourceAsStream(filename));
   }
 
   public static <T> Object[][] getObjectArray(List<T> elements) {   #1
      Object[][] values = new Object[elements.size()][1];
      int counter = 0;
      for (T t : elements) {
         values[counter][0] = t;
         counter++;
      }
      return values;
   }
 
   @DataProvider(name = "users")
   public Object[][] createData() {
      List<User> users = readListData("users.xml");;     
      return getObjectArray(users);                         #B
   }
   …
}
#A Reads the XML with XStream
#1 Transforms list into an array of array
#B Returns data for the tests

Transforming the list into an array of arrays (#1) is done to fit into TestNG’s dataProvider format.

Summary

The reuse of your model can be very handy in data-driven functional tests. There are ten or more parameters you want to check in your user interface. A parameter list becomes even more complicated and results in a lot of work. If you build your user interface around your model, then this is the way you should go. XStream makes it very easy to fill in the important parts of your model.

Here are some other Manning titles you might be interested in:

image003.jpg

Becoming Agile
…in an imperfect world
Greg Smith and Ahmed Sidky

image004.jpg

Specification by Example
Gojko Adzic

image005.jpg

Enterprise Search in Action
Marc Teutelink

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)