Skip to content

Instantly share code, notes, and snippets.

@djangofan
Last active December 25, 2015 19:29
Show Gist options
  • Select an option

  • Save djangofan/7027833 to your computer and use it in GitHub Desktop.

Select an option

Save djangofan/7027833 to your computer and use it in GitHub Desktop.
CSV DataProvider for TestNG in Java
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import au.com.bytecode.opencsv.CSVReader;
public class CsvDataProvider implements Iterator {
/**
* @testng.data-provider name="CsvDataProvider"
* @param method the method the TestNg passes to you
* @return an Iterator of Object[]
*/
public static Iterator getDataProvider(Method method) throws IOException {
return getDataProvider(method.getDeclaringClass(), method);
}
/**
* Call this directly when necessary, to avoid issues
* with the method's declaring class not being the test class.
* @param cls The actual test class - matters for the CsvFileName and the class loader
* @return an Iterator of Object[]
*/
public static Iterator getDataProvider(Class cls, Method method) throws IOException {
String className = cls.getName();
String dirPlusPrefix = className.replace('.', '/');
String fileName = method.getName() + ".csv";
String filePath = dirPlusPrefix + "." + fileName;
return new CsvDataProvider(cls, method, filePath);
}
private CSVReader reader;
private String[] last;
private Class[] parameterTypes;
private Converter[] parameterConverters;
/**
* Basic constructor that will provide the data from the given file for the given method
* @throws IOException when file io fails
*/
public CsvDataProvider(Class cls, Method method, String csvFilePath) throws IOException {
InputStream is = cls.getClassLoader().getResourceAsStream(csvFilePath);
InputStreamReader isr = new InputStreamReader(is);
reader = new CSVReader(isr);
parameterTypes = method.getParameterTypes();
int len = parameterTypes.length;
parameterConverters = new Converter[len];
for (int i = 0; i < len; i++) {
parameterConverters[i] = ConvertUtils.lookup(parameterTypes[i]);
}
}
/**
* @return see Iterator contract.
*/
public boolean hasNext() {
return (getNextLine() != null);
}
/**
* Get the next line, or the current line if it's already there.
* @return the line.
*/
private String[] getNextLine() {
if (last == null) {
try {
last = reader.readNext();
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
return last;
}
/**
* @return the Object[] representation of the next line
*/
public Object next() {
String[] next;
if (last != null) {
next = last;
} else {
next = getNextLine();
}
last = null;
Object[] args = parseLine(next);
return args;
}
/**
* @return the correctly parsed and wrapped values
* @todo need a standard third-party CSV parser plugged in here
*/
private Object[] parseLine(String[] svals) {
int len = svals.length;
Object[] ovals = new Object[len];
for (int i = 0; i < len; i++) {
ovals[i] = parameterConverters[i].convert(parameterTypes[i], svals[i]);
}
return ovals;
}
/**
* Always throws UnsupportedOperationException.
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
import java.lang.reflect.Method;
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.testng.annotations.DataProvider;
public final class CsvDataProvider {
/**
* The {@link DataProvider} method's id used in this class.
* Useful when declaring the {@link DataProvider} to refer the name
*/
public static final String DATA_PROVIDER_ID = "csv-provider";
private static final Log LOG = LogFactory.getLog(CsvDataProvider.class);
private static final char PACKAGE_SEPARATOR_CHAR = '.';
private static final char PATH_SEPARATOR_CHAR = '/';
private static final MessageFormat CLASSPATH_RESOURCE_PATTERN = new MessageFormat("{0}.{1}.test-data.csv");
private static final FieldPosition DEFAULT_FIELD_POSITION = new FieldPosition(0);
private CsvDataProvider() {
// this class can't be instantiated
}
/**
* Builds a lazy data provider starting from a {@link Method}, that provides
* useful informations such its arguments types, used to bind each CSV line
* to proper types.
*
* @param method the method under test
* @return an {@link Iterator} of method's arguments
*/
@DataProvider(name = DATA_PROVIDER_ID)
public static Iterator<Object[]> getDataProvider(Method method) {
String className = method.getDeclaringClass().getName();
String classPathResourceName = className.replace(PACKAGE_SEPARATOR_CHAR, PATH_SEPARATOR_CHAR);
StringBuffer result = new StringBuffer();
Object[] args = new Object[] { classPathResourceName, method.getName() };
CLASSPATH_RESOURCE_PATTERN.format(args, result, DEFAULT_FIELD_POSITION);
String classPathResource = result.toString();
if (LOG.isDebugEnabled()) {
LOG.debug("Looking for classpath resource '" + classPathResource
+ "' to load test data for method '" + method + "'");
}
Class<?>[] types = method.getParameterTypes();
Converter[] typeConverters = new Converter[types.length];
for (int i = 0; i < types.length; i++) {
typeConverters[i] = ConvertUtils.lookup(types[i]);
}
if ( LOG.isDebugEnabled() ) {
LOG.debug("Built new converters array for types " + Arrays.toString(types)
+ ": " + Arrays.toString(typeConverters));
}
return new CsvDataProviderIterator(classPathResource, types, typeConverters);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment