Scala库初始化设计

时间:2014-02-06 16:51:50

标签: java scala properties initialization sbt

我已经启动了一个名为omniprop的开源Scala项目。我目前正在探索的功能是如何允许项目用户堆叠JVM样式的属性提供程序。例如,您可能希望在java.lang.System,Lift的util.Prop和Typesafe的配置库中查找属性。由于omniprop的一些其他约束/特性,我需要将此堆栈配置驻留在已知对象中,因此库的其他部分可以从此堆栈中检索属性。

为了使omniprop正常工作,在访问任何属性之前,需要由库的用户调用此配置。因此,任何使用我的库的项目都需要一个可以设置提供者堆栈的bootstrap / initializer。此初始配置代码的示例如下所示:

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

我面临的挑战特别是测试。为了使用omniprop的项目的测试代码能够工作,它必须以某种方式在运行任何测试之前运行上面的代码。目前,我没有看到使用sbt或我熟悉的任何测试库(如scalatest,scalacheck或specs2)执行此操作的简洁方法。实际上,人们需要在每个测试套件中调用上面的代码片段,这当然不是理想的。

此问题的另一种方法是Lift所做的,其中每个项目都必须有一个名为bootstrap.liftweb.Boot的类,库调用它来设置所有内容。我发现这是一个合理的方法来处理像Lift这样的Web框架,但对于一个小的属性助手库来说似乎太过分了。

我真的有两个问题:

  1. 如何在所有测试运行之前让sbt使用正确的类加载器调用上面的设置代码?
  2. 更重要的是,这是一个需要初始化的库的最佳设计,还是有更好的方法?

2 个答案:

答案 0 :(得分:2)

使用ScalaTest,当我不得不做类似的事情时,我创建了一个扩展BeforeAndAfterAll的特征,我将其混合到需要它的每个套件中。

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

你只需像其他任何特质一样混合它

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

答案 1 :(得分:1)

您可以将初始化代码放在特征构造函数中,让测试从该特征扩展。

另一种方法是将该配置作为默认配置,如果未设置配置,则在第一次调用库代码时使用它。这将涵盖测试和非测试场景。

混合方法是让您的sbt测试配置设置系统属性。如果设置了该系统属性并且未设置任何配置,那么将在第一次调用库代码时使用测试配置。