Добавление к отличному ответу @rmunn:
если вы хотите протестировать myFunc
(да, я также переименовал вашу функцию list
), вы можете сделать это, создав несколько фиксированных случаев, на которые вы уже знаете ответ, например:
let myFunc p = if List.contains " " p || List.contains null p then false else true
let tests =
testList "myFunc" [
testCase "empty list" <| fun()-> "empty" |> Expect.isTrue (myFunc [ ])
testCase "nonempty list" <| fun()-> "hi" |> Expect.isTrue (myFunc [ "hi" ])
testCase "null case" <| fun()-> "null" |> Expect.isFalse (myFunc [ null ])
testCase "empty string" <| fun()-> "\"\"" |> Expect.isFalse (myFunc [ "" ])
]
Tests.runTests config tests
Здесь я использую тестовую библиотеку под названием Expecto
.
Если вы запустите это, вы увидите, что один из тестов не пройден:
Не удалось! myFunc/пустая строка: "". Фактическое значение было истинным, но ожидалось, что оно будет ложным.
потому что в исходной функции есть ошибка; он проверяет наличие пробела " "
вместо пустой строки ""
.
После исправления все тесты проходят:
4 теста выполняются в 00:00:00.0105346 для myFunc — 4 пройдены, 0 проигнорированы, 0 не пройдены, 0 ошибочны. Успех!
На данный момент вы проверили только 4 простых и очевидных случая с нулем или одним элементом в каждом. Много раз функции терпят неудачу при подаче более сложных данных. Проблема в том, сколько еще тестовых примеров вы можете добавить? Возможности буквально безграничны!
фсчек
В этом вам может помочь FsCheck. С помощью FsCheck вы можете проверить свойства (или правила), которые всегда должны быть истинными. Требуется немного творческого подхода, чтобы придумать хорошие для проверки и само собой разумеющиеся, иногда это непросто.
В вашем случае мы можем проверить конкатенацию. Правило будет таким:
- Если два списка объединены, результат
MyFunc
, примененный к объединению, должен быть true
, если оба списка правильно сформированы, и false
, если какой-либо из них сформирован неправильно.
Вы можете выразить это как функцию следующим образом:
let myFuncConcatenation l1 l2 = myFunc (l1 @ l2) = (myFunc l1 && myFunc l2)
l1 @ l2
— это объединение обоих списков.
Теперь, если вы вызовете FsCheck:
FsCheck.Verbose myFuncConcatenation
Он пробует 100 различных комбинаций, пытаясь заставить его потерпеть неудачу, но в конце концов дает вам «ОК»:
0:
["X"]
["^"; ""]
1:
["C"; ""; "M"]
[]
2:
[""; ""; ""]
[""; null; ""; ""]
3:
...
Ok, passed 100 tests.
Это не обязательно означает, что ваша функция верна, все еще может быть ошибочная комбинация, которую FsCheck не пробовал, или она может быть неправильной по-другому. Но это довольно хороший показатель того, что он верен с точки зрения свойства конкатенации.
Тестирование свойства конкатенации с помощью FsCheck фактически позволило нам вызвать myFunc
300 раз с разными значениями и доказать, что оно не давало сбоев и не возвращало неожиданное значение.
FsCheck не заменяет индивидуальное тестирование, а дополняет его:
Обратите внимание, что если бы вы запустили FsCheck.Verbose myFuncConcatenation
поверх исходной функции, в которой была ошибка, она все равно прошла бы успешно. Причина в том, что ошибка не зависит от свойства конкатенации. Это означает, что у вас всегда должно быть индивидуальное тестирование, когда вы проверяете наиболее важные случаи, и вы можете дополнить это с помощью FsCheck для проверки других ситуаций.
Вот другие свойства, которые вы можете проверить, они независимо проверяют два ложных условия:
let myFuncHasNulls l = if List.contains null l then myFunc l = false else true
let myFuncHasEmpty l = if List.contains "" l then myFunc l = false else true
Check.Quick myFuncHasNulls
Check.Quick myFuncHasEmpty
// Ok, passed 100 tests.
// Ok, passed 100 tests.
person
AMieres
schedule
22.11.2018
[null]
. Генератор по умолчанию дляstring list
даст такие входные данные. Вопрос в том, что вы делаете для создания входных данных и как вы их используете. - person scrwtp   schedule 22.11.2018Check.Verbose
. Функцияlist
— это функция проверки, поэтому, конечно, она должна поддаваться фальсификации с любыми входными данными, которые заставляют ее возвращатьfalse
. Вы используете эту функцию для проверки некоторых других функций. - person AMieres   schedule 22.11.2018List.contains " "
проверяет не пустые строки, а строки, содержащие один пробел. Если вы хотите проверить наличие пустых строк, вы должны были написатьList.contains ""
. - person rmunn   schedule 22.11.2018Falsifiable, after 1 test (1 shrink) (StdGen (1956008827,296526183)): Original: [""; "\012"] (At least one control character has been escaped as a char code, e.g. \023) Shrunk: [""]
. Значит ли это, что из-за этого мой тест возвращает false? Я заявил, что это должно быть ложно, и если это ложно, разве это не нормально? - person wolf   schedule 22.11.2018