Начну с sndBigger
- это очень простая функция, но вы можете написать некоторые свойства, которые должны удерживать об этом. Например, что происходит, когда вы полностью изменить значения в кортеже:
// Reversing values of the tuple negates the result
let swap (a, b) = (b, a)
let prop_sndBiggerSwap x =
sndBigger x = not (sndBigger (swap x))
// If two elements of the tuple are same, it should give 'false'
let prop_sndBiggerEq a =
sndBigger (a, a) = false
EDIT: Это правило prop_sndBiggerSwap
не всегда имеет место (см комментарий по KVB). Однако следующее должно быть правильно:
// Reversing values of the tuple negates the result
let prop_sndBiggerSwap a b =
if a <> b then
let x = (a, b)
sndBigger x = not (sndBigger (swap x))
pairs
Что касается функции, KVB уже опубликовал несколько хороших идей. Кроме того, вы можете проверить, что преобразование преобразованного списка в список элементов возвращает исходный список (вам нужно будет обрабатывать случай, когда список ввода нечетный - в зависимости от того, что должно делать функция pairs
в этом случае):
let prop_pairsEq (x:_ list) =
if (x.Length%2 = 0) then
x |> pairs |> List.collect (fun (a, b) -> [a; b]) = x
else true
для splitOn
, мы можем проверить подобную вещь - если вы сцепить все возвращенные списки, он должен дать первоначальный список (это не проверить поведение расщепления, но это хорошая вещь, чтобы начать с - он по крайней мере гарантирует, что никакие элементы не будут потеряны).
let prop_splitOnEq f x =
x |> splitOn f |> List.concat = x
Я не уверен, если FsCheck может справиться с этим, хотя (!), Так как свойство принимает функцию в качестве аргумента (так что потребуется для создания «случайных функций»). Если это не сработает, вам нужно предоставить несколько более конкретных свойств с помощью некоторой рукописной функции f
. Далее, осуществляя проверку, что f
возвращает истинную для всех соседних пар в расщепленных списках (как KVB наводит на мысль) на самом деле не так уж сложно:
let prop_splitOnAdjacentTrue f x =
x |> splitOn f
|> List.forall (fun l ->
l |> Seq.pairwise
|> Seq.forall (fun (a, b) -> f a b))
Вероятно, только последнее, что вы могли бы проверить, что f
возвращает false
, когда вы даете ему последний элемент из одного списка и первый элемент из следующего списка. Ниже не полностью завершен, но она показывает путь:
let prop_splitOnOtherFalse f x =
x |> splitOn f
|> Seq.pairwise
|> Seq.forall (fun (a, b) -> lastElement a = firstElement b)
последний пример показывает также, что вы должны проверить, может ли функция splitOn
возвращает пустой список в качестве части возвращаемого списка результатов (потому что в этом случае вы не смогли найти первый/последний элемент).
Спасибо за советы. Я уже проверяю исключение с xUnit, поэтому нет добавленной стоимости (насколько я могу судить?).На данный момент все это кажется очень сообразительным для меня, и, как вы говорите, в этих конкретных случаях тесты могут быть более сложными, чем оригиналы. – Benjol
Проверки не должны быть более сложными - это действительно поражает цель тестирования. но они могут быть одинаково сложными, по моему опыту. Со временем ваша реализация может стать более сложной (например, оптимизация), в то время как свойства/спецификации обычно остаются более или менее одинаковыми. Поэтому, хотя это может и не иметь смысла, вы, вероятно, будете довольны свойствами позже. –