joescii
joescii

Reputation: 6533

Scala library initialization design

I have started an open source Scala project named omniprop. The feature I'm currently exploring is how to allow users of the project to stack JVM-styled property providers. For instance, you may wish to look up properties in java.lang.System, Lift's util.Prop, and Typesafe's Config library. Due to some other constraints/features of omniprop, I need this stack configuration to reside in a known object, so other parts of the library can retrieve properties from this stack.

In order for omniprop to work correctly, this configuration needs to be invoked by the user of the library before any properties are accessed. Hence any project which uses my library will need a bootstrap/initializer which can set up the provider stack. An example of this initial configuration code looks like this:

import com.joescii.omniprop.providers._
PropertyProviders.configure(List(
  SystemPropertyProvider,
  LiftPropsProvider
))

The challenge I'm facing is with testing in particular. In order for the test code for a project utilizing omniprop to work, it must somehow run the above code before any tests are run. Currently, I don't see a clean way to do this with sbt or any of the testing libraries I am familiar with such as scalatest, scalacheck, or specs2. As it is, one would need to call the above snippet in every test suite, which is certainly not ideal.

Another approach this this problem is what Lift does, in which every project necessarily has a class called bootstrap.liftweb.Boot that the library invokes to set everything up. I find that to be a reasonable approach to a web framework such as Lift, but seems to be too much for a tiny property helper library.

I really have two questions here:

  1. How can I have sbt invoke the above setup code with the correct classloader before all tests run?
  2. More importantly, is this the best design for a library which requires initialization, or is there a better approach?

Upvotes: 1

Views: 183

Answers (2)

leedm777
leedm777

Reputation: 24032

Using ScalaTest, when I've had to do something similar, I created a trait that extends BeforeAndAfterAll, which I mixed into every suite that needed it.

trait Configure extends Suite with BeforeAndAfterAll {
  override def beforeAll() { PropertyProviders.configure(/*...*/); }
  override def afterAll() { PropertyProviders.configure(/*...*/); }
}

You just mix it in like any other trait

trait FooSpec extends Spec with Configure {
  // ...
}

Upvotes: 2

sourcedelica
sourcedelica

Reputation: 24040

You could put the initialization code in a trait constructor and have your tests extend from that trait.

Another approach is to have that configuration as the default, and if no configuration is set then it gets used the first time your library code is called. That would cover both testing and non-testing scenarios.

A hybrid approach would be to have your sbt testing configuration set a system property. If that system property is set and no configuration is has been set then the testing config will be used the first time the library code gets called.

Upvotes: 1

Related Questions