http://stackoverflow.com/questions/11430859/parameters-method-is-executed-before-beforeclass-method
http://stackoverflow.com/questions/11163890/with-junit-4-can-i-parameterize-beforeclass.
What surprises me is that the solutions proposed on SO seem to miss the most obvious workaround - embedding the @BeforeClass in the @Parameters method. The latter is static and is executed only once - before any of the tests.
Here is an example.
I needed a JUnit test that validates all XML files in a particular directory against a schema stored in a particular XSD file. It would be best if the schema is instantiated once - and re-used for all of the individual tests. I tried to encapsulate the schema instantiation in the doSetup() method which I annotated as @BeforeClass. Unfortunately, I got NullPointerException in each of the tests as the @BeforeClass method was, apparently, not called and the schema was therefore not instantiated. Calling the doSetup() method with the @Parameters method data() did the job:
This file contains 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 static org.junit.Assert.assertTrue; | |
import java.io.File; | |
import java.io.IOException; | |
import java.net.URL; | |
import java.util.ArrayList; | |
import java.util.logging.Level; | |
import java.util.logging.Logger; | |
import javax.xml.XMLConstants; | |
import javax.xml.transform.stream.StreamSource; | |
import javax.xml.validation.Schema; | |
import javax.xml.validation.SchemaFactory; | |
import javax.xml.validation.Validator; | |
import org.junit.Test; | |
import org.junit.runner.RunWith; | |
import org.junit.runners.Parameterized; | |
import org.junit.runners.Parameterized.Parameters; | |
import org.xml.sax.SAXException; | |
@RunWith(Parameterized.class) | |
public class XmlValidationTest { | |
private final File xmlFile; | |
static Schema schema; | |
static File xsd; | |
@Parameters(name = "{index}: XML validation of {0}") | |
public static Iterable<Object[]> data() throws SAXException { | |
doSetup();//instead of @BeforeClass | |
ArrayList<File> xmlFiles = listXMLFilesForFolder(xsd.getParentFile()); | |
ArrayList<Object[]> params = new ArrayList<Object[]>(); | |
for (final File fileEntry : xmlFiles) { | |
params.add(new Object[] {fileEntry}); | |
} | |
return params; | |
} | |
public XmlValidationTest(final File xmlFile){ | |
this.xmlFile = xmlFile; | |
} | |
@Test | |
public void xmlValidate() throws IOException{ | |
assertTrue(xmlFile.getName()+" fails", validateXMLSchema(schema, xmlFile)); | |
} | |
//@BeforeClass | |
public static void doSetup() throws SAXException { | |
URL xsdUrl = XmlValidationTest.class.getResource("/tax-invoice179smart.xsd");//included in the mvn test resource folder | |
xsd = new File(xsdUrl.getFile()); | |
Logger.getLogger(XmlValidationTest.class.getName()).log(Level.INFO, "For XmlValidation "+xsd.getName()+" will be used"); | |
SchemaFactory factory = | |
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); | |
schema = factory.newSchema(xsd); | |
} | |
public static boolean validateXMLSchema(Schema schema, File xmlPath) throws IOException { | |
try { | |
Validator validator = schema.newValidator(); | |
validator.validate(new StreamSource(xmlPath)); | |
} catch (SAXException e) { | |
Logger.getLogger(XmlValidationTest.class.getName()).log(Level.SEVERE, e.getMessage()); | |
return false; | |
} | |
return true; | |
} | |
public static ArrayList<File> listXMLFilesForFolder(final File folder) { | |
ArrayList<File> xmlFiles = new ArrayList<File>(); | |
for (final File fileEntry : folder.listFiles()) { | |
if (fileEntry.getName().endsWith(".xml")) { | |
xmlFiles.add(fileEntry); | |
} | |
} | |
return xmlFiles; | |
} | |
} |