Как мы можем имитировать метод scala с общим типом возвращаемого значения и неявными параметрами?

У меня есть сборщик конфигураций, который выглядит примерно так.

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)

Удивительно, кажется, что это ожидание не настроено должным образом. При выполнении теста макет возвращает null.

Любые подсказки о том, как поступить с этим? Пожалуйста, не стесняйтесь, дайте мне знать, если вам нужна дополнительная информация.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
728
3

Ответы 3

Я сильно сомневаюсь, что разные экземпляры неявных ConfigLoader и AppContext передаются в вашем фактическом вызове метода и издеваются над ним. Если вы используете intellij, проверьте, какие имплициты передаются, включив их. Чтобы включить их, нажмите 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)

Большое спасибо, Притам. Следующий код работает.

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)

Вы пробовали мокито-скала? если вы используете новый синтаксис, имплициты будут обрабатываться автоматически (при условии, что вы используете идиоматический синтаксис и одни и те же экземпляры разрешаются в тесте и в вашем производственном коде)

Кроме того, даже если вы используете традиционный синтаксис, ваша заглушка будет сокращена до

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

или если имплициты не совпадают в test и prod (обратите внимание, я также могу смешивать сопоставления аргументов, такие как *, и необработанные параметры, такие как «false»)

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

Другие вопросы по теме