Search code examples
intellij-ideagroovyspock

Spock testing - variables getting null value from the new operator


Below is my test code,

def 'test write then update with commit after all operations parallely'() {
    given:
    def outputPath = "writeThenUpdateWithCommitAfterAllOperationsParallely.csv"
    csvManipulator = new CsvManipulator(RESOURCE_PATH, outputPath, FIELD_COUNT, 0
            , new ResourceReaderProvider(), new FileWriterProvider())

    when:
    GParsPool.withPool 100, {
        (0..LOOP-1).eachParallel { row ->
            writeThenUpdate(row, false)
        }
    }
    csvManipulator.commit()

    then:
    Reader reader = new FileReader(outputPath)
    def outputRawCsv = IOUtils.toString(reader)
    expectedRawCsv == outputRawCsv

    cleanup:
    reader.close()
    Files.delete(Paths.get(outputPath))
}

In short, during debugging mode at each line, I saw all variables outputPath, csvManipulator ... and reader (in the then block) are all null.

Hence, the test ends up in the NullPointerException occurs during closing the null reader.

And that how it looks like in debugging mode: (you can see all the variables are null)

intellij

What happens?


Solution

  • According to the Spock Documentation: "The when and then blocks always occur together. They describe a stimulus and the expected response. Whereas when blocks may contain arbitrary code, then blocks are restricted to conditions, exception conditions, interactions, and variable definitions. A feature method may contain multiple pairs of when-then blocks." Spock blocks

    These two lines:

    Reader reader = new FileReader(outputPath)
    def outputRawCsv = IOUtils.toString(reader)
    

    Need to be in the above when block as shown below:

    def 'test write then update with commit after all operations parallely'() {
        given:
        def outputPath = "writeThenUpdateWithCommitAfterAllOperationsParallely.csv"
        csvManipulator = new CsvManipulator(RESOURCE_PATH, outputPath, FIELD_COUNT, 0
                , new ResourceReaderProvider(), new FileWriterProvider())
    
        when:
        GParsPool.withPool 100, {
            (0..LOOP-1).eachParallel { row ->
                writeThenUpdate(row, false)
            }
        }
        csvManipulator.commit()
        Reader reader = new FileReader(outputPath)
        def outputRawCsv = IOUtils.toString(reader)
    
        then:
        expectedRawCsv == outputRawCsv
    
        cleanup:
        reader.close()
        Files.delete(Paths.get(outputPath))
    }
    

    I would also consider reading the file in using the method Leonard suggested:

    def outputRawCsv = new File(outputPath).text
    

    Adding everything in:

    def 'test write then update with commit after all operations parallely'() {
        given:
        def outputPath = "writeThenUpdateWithCommitAfterAllOperationsParallely.csv"
        csvManipulator = new CsvManipulator(RESOURCE_PATH, outputPath, FIELD_COUNT, 0
                , new ResourceReaderProvider(), new FileWriterProvider())
    
        when:
        GParsPool.withPool 100, {
            (0..LOOP-1).eachParallel { row ->
                writeThenUpdate(row, false)
            }
        }
        csvManipulator.commit()
        def outputRawCsv = new File(outputPath).text
    
        then:
        expectedRawCsv == outputRawCsv
    
        cleanup:
        reader.close()
        Files.delete(Paths.get(outputPath))
    }
    

    If this doesn't work going to need the http://stackoverflow.com/help/mcve