Test Categorization Techniques with TestNG
Pages: 1, 2, 3

Component Tests

Component test have a few aliases, such as subsystem tests or integration tests. Regardless of the desired term, these tests verify portions of an application and may even require a fully installed system or a more limited set of external dependencies, such as databases, file systems, or network endpoints. These tests, in essence, verify that different components interact to produce the expected combined behavior.

A typical component test requires a seeded database; moreover, the test itself may verify behavior across architectural boundaries. Because large amounts of code are exercised by component tests, more code coverage is achieved; however, these tests have the tendency to take longer to run than unit tests.

Because component tests have a cost associated with them—dependencies have to be put in place and configured—they should not be run every time a build is executed. Instead, they should be run at regular intervals. Remember, while these tests alone may only take a few seconds, as more component tests are added to a suite the total test time increases, often quite quickly.

For example, the component test below utilizes DbUnit to seed an underlying database. The set-up alone in this test case takes longer than most unit tests should take to run.

//imports removed...

public class WordDAOImplTest {
 private WordDAO dao = null; 
 /**
  * @testng.before-method = "true" 
  */
 private void setUp() throws Exception {                
  final ApplicationContext context = 
    new ClassPathXmlApplicationContext(
      "spring-config.xml");        
  this.dao = (WordDAO) context.getBean("wordDAO");
 }    
 /**  
  * @testng.before-class = "true" 
  */
 public void oneTimeSetUp() throws Exception{
  final IDatabaseConnection conn = 
    this.getConnection();
  final IDataSet data = this.getDataSet();        
  try{
   DatabaseOperation.CLEAN_INSERT.execute(conn, data);
  }finally{
   conn.close();
  }
 }  
 /**
  * @testng.test
  */
 public void createWord() {       
  final IWord word = new Word();
  word.setSpelling("pabulum");
  word.setPartOfSpeech(
    PartOfSpeechEnum.NOUN.getPartOfSpeech());         
  final IDefinition defOne = new Definition();
  defOne.setDefinition("food");
  defOne.setWord(word);
  final Set defs = new HashSet();
  defs.add(defOne);
  word.setDefinitions(defs);               
  try{
   this.dao.createWord(word);
  }catch(CreateException e){
   Assert.fail("CreateException was thrown");
  }           
 }
 
 private IDataSet getDataSet() 
   throws IOException, DataSetException {
    return new FlatXmlDataSet(
     new File("test/conf/words-seed.xml"));
 }
 
 private IDatabaseConnection getConnection() 
   throws ClassNotFoundException, SQLException {
    final Class driverClass = 
      Class.forName("org.gjt.mm.mysql.Driver");
    final Connection jdbcConnection = DriverManager.
     getConnection("jdbc:mysql://localhost/words", 
      "words", "words");               
  return new DatabaseConnection(jdbcConnection);
}
}

Component tests don't always depend on databases, however. For example, relying on file systems creates a coupling that increases configuration complexity and, in some cases, time. For instance, the component test below uses XMLUnit to verify generated XML. Note that the test relies on a file system path to compare two XML documents.

//imports removed...

public class BatchDepXMLReportValidationTest {
 /**
  * @testng.before-class = "true" 
  */
 protected void configure() throws Exception {        
  XMLUnit.setControlParser(
   "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
  XMLUnit.setTestParser(
   "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
  XMLUnit.setSAXParserFactory(
   "org.apache.xerces.jaxp.SAXParserFactoryImpl");
  XMLUnit.setIgnoreWhitespace(true);   
 }

 private Filter[] getFilters(){            
  return new Filter[] {
   new RegexPackageFilter("java|org"),
   new SimplePackageFilter("junit.")
  };
 }

 private Dependency[] getDependencies(){
  return new Dependency[] {
   new Dependency("com.vanward.resource.XMLizable"),
   new Dependency("com.vanward.xml.Element")
  };        
 }
 /**
  * @testng.test     
  */
 public void assertToXML() throws Exception{
  BatchDependencyXMLReport report = 
   new BatchDependencyXMLReport(
    new Date(9000000), this.getFilters());

  report.addTargetAndDependencies(
   "com.vanward.test.MyTest", this.getDependencies());
  report.addTargetAndDependencies(
   "com.xom.xml.Test", this.getDependencies());

  Diff diff = new Diff(new FileReader(
   new File("./test/conf/report-control.xml")),
    new StringReader(report.toXML()));

  Assert.assertTrue(
   diff.identical(),"XML was not identical");        
 }
}

While component tests shouldn't be executed every time a build is run, it's a good bet to run them before committing code into a repository. In a continuous integration environment it's probably a good idea to run these at frequent intervals, such as hourly.

Pages: 1, 2, 3

Next Page »