【问题标题】:How do I test code that requires an Environment Variable?如何测试需要环境变量的代码?
【发布时间】:2021-04-23 20:16:00
【问题描述】:

我有一些代码需要环境变量才能正确运行。但是当我运行我的单元测试时,它一旦到达那个点就会爆炸,除非我专门在终端中导出变量。我正在使用 Scala 和 sbt。我的代码是这样的:

class something() {

  val envVar = sys.env("ENVIRONMENT_VARIABLE")

  println(envVar)

}

如何在我的单元测试中模拟它,以便在调用 sys.env("ENVIRONMENT_VARIABLE") 时返回一个字符串或类似的东西?

【问题讨论】:

  • 我会在单独的服务中包装检索环境变量并在测试时模拟它
  • 如果无法包装现有代码,可以更改 UnmodifiableMap System.getenv() 进行测试。

标签: scala unit-testing environment-variables


【解决方案1】:

如果您无法包装现有代码,您可以更改 UnmodifiableMap System.getenv() 以进行测试。

def setEnv(key: String, value: String) = {
  val field = System.getenv().getClass.getDeclaredField("m")
  field.setAccessible(true)
  val map = field.get(System.getenv()).asInstanceOf[java.util.Map[java.lang.String, java.lang.String]]
  map.put(key, value)
}

setEnv("ENVIRONMENT_VARIABLE", "TEST_VALUE1")

如果您需要测试控制台输出,您可以使用单独的 PrintStream。 您也可以实现自己的 PrintStream。

val baos = new java.io.ByteArrayOutputStream
val ps = new java.io.PrintStream(baos)
Console.withOut(ps)(
  // your test code
  println(sys.env("ENVIRONMENT_VARIABLE"))
)

// Get output and verify
val output: String = baos.toString(StandardCharsets.UTF_8.toString)
println("Test Output: [%s]".format(output))
assert(output.contains("TEST_VALUE1"))

【讨论】:

  • setEnv 很有用。谢谢。在我的单元测试中,我可以在创建对象之前调用它并验证新值是否被拾取。
  • 跟进:嗯。尽管该方法声称有效,但调用它似乎并没有改变环境。叹。需要更多研究。
【解决方案2】:

理想情况下,应该重写环境访问以安全地检索数据。要么使用默认值...

scala> scala.util.Properties.envOrElse("SESSION", "unknown")
res70: String = Lubuntu

scala> scala.util.Properties.envOrElse("SECTION", "unknown")
res71: String = unknown

...或作为一个选项...

scala> scala.util.Properties.envOrNone("SESSION")
res72: Option[String] = Some(Lubuntu)

scala> scala.util.Properties.envOrNone("SECTION")
res73: Option[String] = None

...或两者兼而有之[参见envOrSome()]。

我不知道有什么方法可以让它看起来像设置了任何/所有随机环境变量,但在运行测试之前没有实际设置它们。

【讨论】:

  • 默默地使用假值(“未知”)而不是抛出异常似乎并不安全。
  • @stackexchanger,“一种安全的方式”,在这种情况下,仅表示:除非在设计中指定,否则不会抛出异常。这一切都取决于设计要求。如果设计不允许约定的默认值(不是“假”),则使用Option[] 选项。
【解决方案3】:

你不应该在单元测试中测试它。

把它提取出来

class F(val param: String) {
  ...
}

在你的产品代码中你做

new Foo(sys.env("ENVIRONMENT_VARIABLE"))

【讨论】:

    【解决方案4】:

    我会将配置封装在一个不公开实现的装置中,可能是一个类 ConfigValue

    我会将实现放在类 ConfigValueInEnvVar extends ConfigValue

    这允许我测试依赖于 ConfigValue 的代码,而无需设置或清除环境变量。

    它还允许我测试将值作为单独功能存储在环境变量中的基本实现。

    它还允许我将配置存储在数据库、文件或其他任何内容中,而无需更改我的业务逻辑。

    我选择应用层中的实现。 我将环境变量逻辑放在支持域中。 我将业务逻辑和特征/接口放在核心域中。

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2021-08-10
      • 1970-01-01
      • 2015-11-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      相关资源
      最近更新 更多