Стратегия юнит-тестирования в Scala с Try, Success, Failure - PullRequest
0 голосов
/ 07 ноября 2018

Для простоты предположим, что у нас есть метод с именем listTail, который определен следующим образом:

private def listTail(ls: List[Int]): List[Int] = {
 ls.tail
}

Также у нас есть метод, который обрабатывает исключение, когда список пуст.

private def handleEmptyList(ls: List[Int]): List[Int] = {
 if(ls.isEmpty) List.empty[Int]
}

Теперь я хочу создать безопасную версию метода listTail, который использует оба метода:

import scala.util.{Try, Success, Failure}

def safeListTail(ls: List[Int]): List[Int] = {
 val tryTail: Try[List[Int]] = Try(listTail(ls))
 tryTail match {
   case Success(list) => list
   case Failure(_) => handleEmptyList(ls)
 }
}

У меня вопрос: если два частных метода уже проверены, то должен ли я также проверить безопасный метод? И если да, то как? Я думал просто проверить, выполняются ли случаи сопоставления с образцом в зависимости от ввода. То есть, когда мы обращаемся к случаю сбоя, выполняется метод handleEmptyList. Но теперь я знаю, как это проверить.

Или мне нужно реорганизовать мой код и поместить все в один метод? Хотя, возможно, мои личные методы намного сложнее, чем в этом примере.

Мой тест написан с использованием ScalaTest.

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

На самом деле все наоборот: обычно вы не хотите тестировать приватные методы, только публичные, потому что именно они определяют ваши взаимодействия с внешним миром, если они работают, как обещано, Кого волнует, что делают ваши частные методы, это просто детали реализации.

Итак, суть в следующем - просто протестируйте ваш safeListTail, и все, не нужно тестировать внутреннюю реализацию отдельно.

Кстати, вам не нужно match там: Try(listTail(ls)).getOrElse(handleEmptyList(ls)) эквивалентно тому, что у вас там ... что на самом деле не очень хорошая идея, потому что оно поглощает другие исключения, а не только те, которые есть Брошенный, когда список пуст, лучше было бы восстановить match, но избавиться от Try:

  ls match {
     case Nil => handleEmptyList(ls)
     case _ => listTail(ls)
  }
0 голосов
/ 07 ноября 2018

Позволить вашим методам бросать преднамеренно - плохая идея и определенно не в духе FP. Вероятно, лучше регистрировать сбой в сигнатуре типа методов, которые могут давать сбой.

private def listTail(ls: List[Int]): Try[List[Int]] = Try {
  ls.tail
}

Теперь ваши пользователи знают, что это вернет либо Success, либо Failure, и волшебная стопка не будет развернута. Это уже облегчает тестирование этого метода.

Вы также можете избавиться от соответствия шаблону с помощью простого def safeTailList(ls: List[Int]) = listTail(l).getOrElse(Nil) с помощью этой формулировки - довольно приятно!

Если вы хотите проверить это, вы можете сделать его закрытым и протестировать его соответствующим образом.

Лучше было бы пересмотреть ваш алгоритм. Есть техника, которая делает получение безопасного хвоста встроенным:

def safeTailList(ls: List[Int]) = ls.drop(1)
...