TestNG Lazy DataProvider with Factory

Last week I ran into an issue passing a lazy dataprovider to a factory. The following is the issue I first ran into:

The issue I was having is that when I ran my class it ran X (# of .xml files) number of tests using the last value contained in the array.

So if I had [“Oregon.xml”, “NewYork.xml”, “Washingtion.xml”] Washington will run 3 times.
class supplyData{

    @DataProvider
    public static Iterator<Object[]> loadStatePages(){

        List<Object[]> allParsedXMLPages = new ArrayList<Object[]>()
        int loadNextState = 0

        //create array containing x "StatePage.xml"; where x = # of states
        def allStatePages = getCityStatePages("State")

        allStatePages.each {singleStatePage ->
            def loadedStatePage = loadFile(singleStatePage)

            //create array containing [0]STATENAME, [2]ABBREVNAME, [3]ARRAY CITYNAMES
            def allStates = getStateContainer()

            //load next state to load into currentState
            def currentState = allStates[loadNextState]

            def fullStateName = currentState[0].toString()
            def abbrevState = currentState[1].toString()

            //create allCities by remove the fullStateName and abbrevState from array
            def allCities = currentState
            allCities.remove(0)
            allCities.remove(0)

            def cityLink = ""

            for (city in allCities) {
                def cityHref = city.text().replaceAll(/\W+/, '-')
                cityLink = cityLink +('<link>\n' +
                        '<title>'+ city + '</title>\n' +
                        '<linktext>' + city + '</linktext>\n' +
                        '<asserthref>/' + cityHref.toLowerCase() + '</asserthref>\n' +
                        '<asserttitle>' + city + ", " + fullStateName + '</asserttitle>\n' +
                        '</link>\n'
                )
            }

            String bodyStatePage = loadedStatePage.getText()

            ++loadNextState

            def parsedStatePage = parseString(bodyStatePage)

            def completeStatePage = createFullXMLPage(bodyStatePage, parsedStatePage)

            //add the parsed page to our ArrayList
            allParsedXMLPages.add(completeStatePage as Object[])
        }

        return allParsedXMLPages.iterator()
    }
}
public class CityTests{
    static cityCurrentXML

    public CityTests(newXML){
        this.cityCurrentXML = newXML
    }

    @Factory (dataProviderClass=supplyData.class, dataProvider="loadCityPages")
    public static Object[] getNextXML(cityCurrentXML){
        return [new CityTests(cityCurrentXML)]
    }

    @BeforeClass
    void openBrowser(){
        startBrowser()
    }

    @Test (description="Check MetaTags for correct content")
    public void MetaTags(){
        def errors = testMetaTags(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Links for existance, clickability, and target")
    public void Links(){
        def errors = testLinks(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Text for existance and accuracy")
    public void Text(){
        def errors = testText(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Overlays for existance, links, and text")
    public void Overlays(){
        def errors = testOverlays(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Hovers for existance, links, and text")
    public void Hovers(){
        def errors = testHovers(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }
    @Test (description="Check Inputs for existance, typeability, and target")
    public void Inputs(){
        def errors = testInputs(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Sliders for existance, links, and text")
    public void Sliders(){
        def errors = testSliders(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Images for existance and display")
    public void Images(){
        def errors = testImgLoaded(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check AtlasTags for existance and value")
    public void AtlasTags(){
        def errors = testAtlas(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @AfterClass
    void tearDown(){
        driver.quit()
    }
}
To fix this issue I had to make the following changes:
class supplyData{

class supplyData{

    @DataProvider
    public static Object[][] loadStatePages(){

        List<Object[]> allParsedXMLPages = new ArrayList<Object[]>()
        int loadNextState = 0

        //create array containing x "StatePage.xml"; where x = # of states
        def allStatePages = getCityStatePages("State")

        allStatePages.each {singleStatePage ->
            def loadedStatePage = loadFile(singleStatePage)

            //create array containing [0]STATENAME, [2]ABBREVNAME, [3]ARRAY CITYNAMES
            def allStates = getStateContainer()

            //load next state to load into currentState
            def currentState = allStates[loadNextState]

            def fullStateName = currentState[0].toString()
            def abbrevState = currentState[1].toString()

            //create allCities by remove the fullStateName and abbrevState from array
            def allCities = currentState
            allCities.remove(0)
            allCities.remove(0)

            def cityLink = ""

            for (city in allCities) {
                def cityHref = city.text().replaceAll(/\W+/, '-')
                cityLink = cityLink +('<link>\n' +
                        '<title>'+ city + '</title>\n' +
                        '<linktext>' + city + '</linktext>\n' +
                        '<asserthref>/' + cityHref.toLowerCase() + '</asserthref>\n' +
                        '<asserttitle>' + city + ", " + fullStateName + '</asserttitle>\n' +
                        '</link>\n'
                )
            }

            String bodyStatePage = loadedStatePage.getText()

            ++loadNextState

            def parsedStatePage = parseString(bodyStatePage)

            def completeStatePage = createFullXMLPage(bodyStatePage, parsedStatePage)

            //add the parsed page to our ArrayList
            allParsedXMLPages.add(completeStatePage as Object)
        }

        return allParsedXMLPages
    }
}
public class CityTests{
    private cityCurrentXML

    public CityTests(newXML){
        this.cityCurrentXML = newXML
    }

    @Factory (dataProviderClass=supplyData.class, dataProvider="loadCityPages")
    public static Object[] getNextXML(cityCurrentXML){
        return [new CityTests(cityCurrentXML)]
    }

    @BeforeClass
    void openBrowser(){
        startBrowser()
    }

    @Test (description="Check MetaTags for correct content")
    public void MetaTags(){
        def errors = testMetaTags(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Links for existance, clickability, and target")
    public void Links(){
        def errors = testLinks(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Text for existance and accuracy")
    public void Text(){
        def errors = testText(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Overlays for existance, links, and text")
    public void Overlays(){
        def errors = testOverlays(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Hovers for existance, links, and text")
    public void Hovers(){
        def errors = testHovers(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }
    @Test (description="Check Inputs for existance, typeability, and target")
    public void Inputs(){
        def errors = testInputs(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Sliders for existance, links, and text")
    public void Sliders(){
        def errors = testSliders(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check Images for existance and display")
    public void Images(){
        def errors = testImgLoaded(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @Test (description="Check AtlasTags for existance and value")
    public void AtlasTags(){
        def errors = testAtlas(cityCurrentXML)

        assertPageTest(errors, cityCurrentXML.PAGENAME.text())
    }

    @AfterClass
    void tearDown(){
        driver.quit()
    }
}
As you can see I removed the lazy dataProvider as I was unable to pass the object correctly to the factory. The main issue I had was when passing the object to a static variable the factory recreate the class with the last loaded static value. Hope this helps you get a dataProvider with factory working correctly for you!
Justin