Если добавить превосходный ответ @ 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 может вам помочь.С помощью FsCheck вы можете проверить свойства (или правила), которые всегда должны быть истинными.Требуется немного творческого подхода, чтобы подумать о хороших, чтобы проверить и получить, а иногда это нелегко.
В вашем случае мы можем проверить на конкатенацию.Правило будет выглядеть следующим образом:
- Если два списка объединены, то результат
MyFunc
, примененный к объединению, должен быть true
, если оба списка правильно сформированы, и false
, если любой из нихискажен.
Вы можете выразить это как функцию следующим образом:
let myFuncConcatenation l1 l2 = myFunc (l1 @ l2) = (myFunc l1 && myFunc l2)
l1 @ l2
- это объединение обоих списков.
Теперь, если выcall FsCheck:
FsCheck.Verbose myFuncConcatenation
Он пробует 100 различных комбинаций, пытаясь заставить его потерпеть неудачу, но в конце он дает вам Ok:
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.