Last active
December 25, 2015 19:29
-
-
Save djangofan/7027833 to your computer and use it in GitHub Desktop.
CSV DataProvider for TestNG in Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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