Venki
Venki

Reputation: 1459

Ordering jbehave stories to run sequentially

I am trying to run jbehave stories in a sequence.

My package structure for Integration tests is shown below

src/it/some/package/name/packageA/a.story
src/it/some/package/name/packageB/b.story
src/it/some/package/name/c.story

I want the story to be run in this sequence a.story, b.story, c.story

I tried using GivenStories in jBehave but they didn't seem to work (may be I am not specifying them correctly). I would very much appreciate it if someone could point to the creation of GivenStories text and also show some insight as to how jbehave creates the ordering when it runs the Integration tests because I see that running stories on my machine and on jenkins seems to be yielding different execution ordering.

Any help on this is greatly appreciated. Thanks!

Upvotes: 1

Views: 4636

Answers (3)

chrisA
chrisA

Reputation: 117

The reason this happens is because JBehave runs tests in the order in which it finds them in the filesystem. To avoid this, you can extend JBehave's StoryFinder class and override findClassNames() to use an ordered list which you have stored somewhere (a properties file, build.xml, etc):

@Override
public List<String> findClassNames(String searchIn, List<String> includes, List<String> excludes) {

    String[] orderedTestListArray = retrtieveTestNamesFromBuildXml();

    List<String> scannedTestList = scan(searchIn, includes, excludes);
    System.out.println("Scanned Test List: " + scannedTestList);

    List<String> finalTestList = new ArrayList<String>();
    for(String x: orderedTestListArray) {
        for(String y: scannedTestList) {
            if(y.contains(x))
                finalTestList.add(y);
        }
    }

    System.out.println("Final Ordered Test List: " + finalTestList);
    return classNames(normalise(finalTestList));
}

In this case, I am retrieving the orderedTestListArray by parsing my ant build.xml file which includes the list of ordered tests I want to run:

private String[] retrtieveTestNamesFromBuildXml() {
    String[] orderedTestListArray = null;
    InputStream iStream = null;
    try {
        File file = new File("build.xml");

        if(file.exists()) {
           iStream = new FileInputStream(file);
           DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
           DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
           Document doc = docBuilder.parse(iStream);       
           NodeList propertyNodes = doc.getElementsByTagName("property");

           String orderedTestListString = null;

           for (int i = 0; i < propertyNodes.getLength(); i++) {
               Element elementNode = (Element) propertyNodes.item(i);
               if(elementNode.getAttribute("name").equals("xed.tests.to.run")) {
                   orderedTestListString = elementNode.getAttribute("value");
                   break;
               }      
           }

           orderedTestListArray = orderedTestListString.split(",");
           for(int i = 0; i <= orderedTestListArray.length-1; i++) {
               orderedTestListArray[i] = orderedTestListArray[i].trim();
               orderedTestListArray[i] = orderedTestListArray[i].substring(3, orderedTestListArray[i].length());
           }
        }  
     }
     catch (Exception e) {
         System.out.println("Error parsing XML info from build.xml");
         e.printStackTrace();
         System.exit(1);
     }
    finally {
        try
        {
            if(iStream != null)
                iStream.close();
        }
        catch (IOException e)
        { 
            System.out.println("Error closing InputStream for build.xml");
            e.printStackTrace();
        }
    }
    return orderedTestListArray;
}

Finally, make sure you specify this new StoryFinder class while running from ant or maven as follows:

storyFinderClass=fullyQualifiedNameOfNewStoryFinderClass

Upvotes: 1

Venki
Venki

Reputation: 1459

I actually figured out a work around on this issue which i thought was much convenient than GivenStories

First i added a maven surefire configuration like this

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>${surefire.version}</version>
  <configuration>
    <includes>
       <include>**/*TesterSequence.java</include>
    </includes>
  </configuration>
</plugin>

The SampleTesterSequence would be structured like the one shown below

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;



@RunWith(Suite.class)
@Suite.SuiteClasses({ A.class,B.class, 
        C.class })
public class SampleTesterSequence {
    @BeforeClass
    public static void beforeStories() throws Exception {
       //TODO Implement before story steps
    }

    @AfterClass
    public static void afterStories() throws Exception {
      //TODO Implement after story steps
    }
}

As you can see the the suite will run the stories a,b,c in the sequence i mention with the suite, when surefire runs the tests it looks for a pattern ending with TesterSequence and will run that class first and from that class it executes the stories we want to run in that order specified.

Upvotes: 1

StripLight
StripLight

Reputation: 439

Guess this response might be a bit late, but anyway. We're trying out JB also,still seems to be plenty of issues around making this work, esp for anything real world.

We have given stories working within a module, but if you try and invoke across modules (eg you have a dependent jar which holds a common story you'd like to call, then this doesn't seem to work at all).

In the same module though, make sure you place the GS entry in the right place in the story, as follows:

Story: Running BBB

GivenStories: com/xxx/test/stories/test_aaa_user.story

Given a BBB string
When I set BBB to activate
Then the BBB string is set to activate

This runs the AAA story before the BBB one.

Upvotes: 2

Related Questions