Search code examples
scalasbtscalatest

How Can I Share Code Between Integration Tests and Unit Tests


For my tests I have created an object which holds all my Arbitrary instances of case classes (ie my generators):


object Generators
    extends
    FooGen
  {


  def sample[A](implicit gen: Gen[A]): A =
    gen.sample.getOrElse(sys.error(s"Could not generate instance with $gen"))

  implicit def arb[A](implicit g: Gen[A]): Arbitrary[A] = Arbitrary(g)

}

trait FooGen { this: GenUtils =>

  implicit val fooGen: Gen[Foo] = gen[Foo]

}

This currently sits under my /test folder as I need it to generate arbitrary instances of my cases classes for my unit tests. But now I want to create some integration tests which will be under my /it folder. What is the best way to share this generator file in my /test folder with my tests in /it folder?

I will have lots of these generators for all my case classes so I don't want to duplicate the code so that is why I am asking.


Solution

  • Based on gilad hoch's answer try

    IntegrationTest / dependencyClasspath := 
      (IntegrationTest / dependencyClasspath).value ++ (Test / exportedProducts).value
    

    for example your build.sbt might look like

    lazy val root = (project in file("."))
      .configs(IntegrationTest)
      .settings(
        Defaults.itSettings,
        libraryDependencies += scalaTest % "it,test",
        IntegrationTest / dependencyClasspath :=
          (IntegrationTest / dependencyClasspath).value ++ (Test / exportedProducts).value
      )
    

    and the directory structure

    ├── it
    │   └── scala
    │       └── example
    │           └── GoodbyeSpec.scala
    ├── main
    │   └── scala
    │       └── example
    │           └── Hello.scala
    └── test
        └── scala
            └── example
                ├── FooGen.scala
                └── HelloSpec.scala
    

    so now FooGen.scala is accessible from GoodbyeSpec.scala.

    Another option is creating a multi-project build and factor out common test code into its own project, perhaps test-common, and then have the main project depend on it

    lazy val core = (project in file("core"))
      .dependsOn(testCommon)
      .settings(
        // other settings
      )
    
    lazy val testCommon = (project in file("testCommon"))
      .settings(
        // other settings
      )