我们如何使用泛型返回类型和隐式参数来模拟scala方法?

问题描述 投票:0回答:3

我有一个看起来像这样的配置提取器。

def getForCountry[A](path: String, fallbackToDefault: Boolean)
                  (implicit loader: ConfigLoader[A], ac: AppContext): A = {
configuration.getOptional[A](s"${ac.country}.$path") match {
  case Some(value)                =>
    value
  case None if fallbackToDefault  =>
    configuration.get[A](path)
  case None if !fallbackToDefault =>
    throw new RuntimeException(s"${ac.country}.$path key not found in configuration")
}

调用相同的方法如下 -

val countrySpecificConfig =
  configurationHelper.getForCountry[Map[String, String]]("googleCloudPlatform.jobConfig.demandBasedPricing", fallbackToDefault = false)

现在我想在单元测试中模拟getForCountry方法 -

when(configurationHelper
    .getForCountry[Map[String, String]]("googleCloudPlatform.jobConfig.demandBasedPricing", fallbackToDefault = false))
    .thenReturn(countryPricingWeekConfiguation)

令人惊讶的是,似乎没有正确设置这种期望。在执行测试时,mock返回null。

有关如何进行此操作的任何线索?如果您需要任何进一步的细节,请随时告诉我。

scala unit-testing playframework mockito expectations
3个回答
1
投票

我强烈怀疑隐含的ConfigLoaderAppContext的不同实例是在实际的方法调用中传递并模拟了一个。如果您正在使用intellij,请通过启用它们来验证通过哪些implicits。要启用它们,请按ctr+alt+shift++

这是完整的测试模拟你的情况,工作得很好:

test("mock example") {
    trait ConfigLoader[T] {}

    trait AppContext { def country: String }

    trait ConfigurationHelper {
      def getForCountry[A](x: String, fallbackToDefault: Boolean = true)(implicit loader: ConfigLoader[A], ac: AppContext): A
    }

    implicit val loader: ConfigLoader[Map[String, String]] = mock[ConfigLoader[Map[String, String]]]
    implicit val ctx: AppContext                           = mock[AppContext]
    val configurationHelper                                = mock[ConfigurationHelper]

    val mockedResult = Map("x" → "1")

    when(
      configurationHelper
        .getForCountry[Map[String, String]]("googleCloudPlatform.jobConfig.demandBasedPricing", fallbackToDefault = false)
    ).thenReturn(mockedResult)

    val countrySpecificConfig =
      configurationHelper
        .getForCountry[Map[String, String]]("googleCloudPlatform.jobConfig.demandBasedPricing", fallbackToDefault = false)

    countrySpecificConfig.foreach(println)
  }

// =========================== Output ====================
// (x,1)


0
投票

非常感谢Pritam。以下代码似乎有效。

when(configurationHelper
    .getForCountry[Map[String, String]]
    (ArgumentMatchers.eq("googleCloudPlatform.jobConfig.demandBasedPricing"), ArgumentMatchers.eq(false))
    (ArgumentMatchers.any[ConfigLoader[Map[String, String]]](), ArgumentMatchers.any[AppContext]()))
    .thenReturn(countryPricingWeekConfiguation)

0
投票

你试过mockito-scala吗?如果您使用新语法,将自动处理implicits(假设您使用惯用语法并在测试和prod代码中解析相同的实例)

即使您使用传统语法,您的存根也会减少到

when(configurationHelper
    .getForCountry[Map[String, String]]
    (eqTo("googleCloudPlatform.jobConfig.demandBasedPricing"), eqTo(false))(*, *)
    .thenReturn(countryPricingWeekConfiguation)

或者用惯用语法

configurationHelper.getForCountry[Map[String, String]]
    ("googleCloudPlatform.jobConfig.demandBasedPricing",false)
    shouldReturn countryPricingWeekConfiguation

或者如果测试和产品中的含义不一样(请注意我也可以混合使用像*和原始参数这样的'假'的arg匹配器)

configurationHelper.getForCountry[Map[String, String]]
    ("googleCloudPlatform.jobConfig.demandBasedPricing",false)(*,*)
    shouldReturn countryPricingWeekConfiguation
© www.soinside.com 2019 - 2024. All rights reserved.