Scala избегать спящего потока для асинхронных тестовых случаев - PullRequest
2 голосов
/ 06 марта 2020

Я пишу модульные тесты для метода, который запускает основную функцию и затем асинхронно записывает подробности о запросе.

def someMethod(data: Object): SomeType =
  for {
    result <- someOtherMethod(data).withLogging(logMethod)
  }

Метод logMethod является асинхронной c задачей. В моих тестах я хочу убедиться, что регистратор получает сообщение, однако поток завершается слишком быстро, время от времени делая тест нестабильным и иногда вызывая результат Unsatisfied.

Пример теста:

it("logs an error if an upload was attempted with some failure case") {
  val uploadData = someData

  mockSomeCall()

  mockAnotherCall()

  testController.methodWeAreTesting(uploadData).shouldBeRight()

  Thread.sleep(75)

  (stubLogger
    .warn(_: RichMsg, _: Throwable, _: AnyId)(_: () => SourceLocation))
    .verify(where { (msg: RichMsg, _, _, _) =>
      msg.toString.equals(s"Some specific message")
     })
}

Мне не нравится добавлять Thread.sleep каждый раз, когда мне нужно убедиться, что регистратор получает указанное c сообщение. Я хотел бы иметь возможность обернуть ожидание stubLogger.

Дайте мне знать, если потребуется дополнительная информация.

1 Ответ

0 голосов
/ 06 марта 2020

Я думаю, promise - это то, что вам нужно добавить в logMethod. Согласно документации :

Хотя фьючерсы определены как тип объекта-заполнителя только для чтения, созданный для результата, который еще не существует, можно подумать об обещании как доступный для записи контейнер с одним назначением, который завершает будущее. Таким образом, обещание может быть использовано для успешного завершения будущего со значением (путем «завершения» обещания) с использованием метода успеха. И наоборот, обещание также можно использовать для завершения будущего с исключением, если оно не выполнено и используется метод сбоя.

Обещание p завершает будущее, возвращаемое p.future. Это будущее определяется c обещанием с. В зависимости от реализации, это может быть случай, когда p.future eq p.

В тестах, как только вы вернете результат, вы можете сравнить результат с сообщением, которое вы пытаетесь сравнить.

Пример кода показан ниже:

object Test1 extends App {
  import scala.concurrent.{Future, Promise}
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.util.{Success, Failure}

  var promiseMessage: String = _
  val promise = Promise[String] //The promise will hold a string

  //A future tells the System to spawn a new thread and run the code block inside it
  val logMethod =  (elem: String) => Future{
    promise.success(elem)
    elem
  }

  def method(data: String): Future[String] = {
    for {
      result <- logMethod(data)
    } yield result
  }

  val f1 = method("Hi!! I love scala async programming")

  promise completeWith f1
  val promiseFuture = promise.future

  promiseFuture onComplete {
    case Success(value) =>
      promiseMessage = value
      println(promiseMessage)
    case Failure(ex) => println(ex)
  }

  Await.result(promiseFuture, 100 seconds)

  if (promiseMessage == "Hi!! I love scala async programming") println("correct")
}

В коде promise - это объект Promise, который обещает строку, когда будущее завершится. Все, что вам нужно сделать, это выполнить обещание с будущим, как показано в: promise completeWith f1, а затем добавьте обработчик того, что делать в случае успеха или неудачи, используя promiseFuture onComplete.

Если вы хотите проверить, произошла ли регистрация, вы можете await на promiseFuture или продолжить дальнейший процесс, и когда запись будет завершена, будет напечатано успешное обещание, как показано в коде.

Дайте мне знать это помогает !!

...