Search code examples
filejunitspecs2

How to use jUnit's TemporaryFolder in scala's specs2 tests?


I'm writing a test with Playframework, and I need to create a temporary file.

@RunWith(classOf[JUnitRunner])
class DiagnosticSpec extends Specification {
  @Rule
  val temporaryFolder: TemporaryFolder = new TemporaryFolder()

  "my test" should {
     "run with temporary file" in {
        val file = temporaryFolder.newFile()   // line.35
        // go on with the file
     }
  }
}

But when I run this test, it always throw exception:

[error]     IllegalStateException: the temporary folder has not yet been created (MyTest.scala:35)

Is it possible to use it in specs2? If not, how can I create a temporary file in specs2, and delete it automatically after testing?


Solution

  • You cannot use JUnit rules with specs2 to do setup/teardown. You need to use AroundExample or FixtureExample for that:

    trait TempFile extends AroundExample {
      // this code is executed "around" each example
      def around[R : AsResult](r: =>Result) = 
        val f = createFile("test")
        try AsResult(r)
        finally f.delete
    }
    
    class MySpec extends Specification with TempFile {
      "test" >> {
        // use the file here
        val file = new File("test")
        ...
      }
    }
    
    // Or
    trait TempFile extends FixtureExample[File] {
      // this code is executed "around" each example
      def fixture[R : AsResult](f: File => R) = 
        val f = createFile("test")
        try AsResult(f(r))
        finally f.delete
    }
    
    class MySpec extends Specification with TempFile {
      // the file can be "injected" for each test
      "test" >> { file: File =>
        // use the file here
        ...
      }
    }
    

    UPDATE

    The TemporaryFolder trait is closer to the original JUnit rule:

    trait TemporaryFolder extends Specification {
      /** delete the temporary directory at the end of the specification */
      override def map(fs: => Fragments): Fragments = {
        super.map(fs.append(step(delete)))
      }
    
      lazy val tempDir = {
        val dir = File.createTempFile("test", "")
        dir.delete
        dir.mkdir
        dir
      }
    
      /** create a new file in the temp directory */
      def createNewFile = {
        val f = new File(tempDir.getPath+"/"+UUID.randomUUID.toString)
        f.createNewFile
        f
      }
    
      /** delete each file in the directory and the directory itself */
      def delete = {
        Option(tempDir.listFiles).map(_.toList).getOrElse(Nil).foreach(_.delete)
        tempDir.delete
      }
    }
    
    class MySpec extends Specification with TemporaryFolder {
      "test" >> {
        // use the file here
        val file = createNewFile
        ...
      }
    }