我想在 F# 中使用 xUnit 对这段代码进行单元测试。我如何处理这些选项?
来自 Scott Wlaschin 的书:Domain Modeling Made Functional
type UnitQuantity = private UnitQuantity of int
// ^ private constructor
// define a module with the same name as the type
module UnitQuantity =
/// Define a "smart constructor" for UnitQuantity
/// int -> Result<UnitQuantity,string>
let create qty =
if qty < 1 then
// failure
Error "UnitQuantity can not be negative"
else if qty > 1000 then
// failure
Error "UnitQuantity can not be more than 1000"
else
// success -- construct the return value
Ok (UnitQuantity qty)
Run Code Online (Sandbox Code Playgroud)
测试:
let ``Check UnitQuantity.create is one`` () =
// ARRANGE
let expected = 1
// ACT
//let unitQtyResult = UnitQuantity.create 1
match UnitQuantity.create 1 with
| Error msg -> 0
//printfn "Failure, Message is %s" msg
| Ok x -> 0
// let innerValue = UnitQuantity.value actual
// ASSERT
//Assert.Equal(expected,actual)
Run Code Online (Sandbox Code Playgroud)
我知道这ACT
一切都错了,这就是我挂断电话的地方。我对 F# 选项、xUnit.net 或单元测试的了解不够充分,无法断言函数的实际值。
我可能会直接比较结果而不是模式匹配。但是,由于构造函数的原因,您无法为其创建Ok
结果。Result<UnitQuantity, string>
private
您可以使用内置函数Result.map
来映射Ok
结果的值。使用UnitQuantity.value
您可以映射Result<UnitQuantity, string>
到Result<int, string>
。所以这应该有效:
let expected = Ok 1
let actual = UnitQuantity.create 1 |> Result.map UnitQuantity.value
Assert.Equal(expected, actual)
Run Code Online (Sandbox Code Playgroud)
单元测试的一般经验法则是 Act 部分应该是单个语句。
我们想要检查结果的所有内容都是某种形式的断言
所以我们想要断言结果是 anOk<UnitQuantity>
还是 an Error<string>
。
这是模式匹配允许我们非常简洁地测试的地方
let ``Check UnitQuantity.create is one`` () =
// ARRANGE
let qty = 1 // The quantity we supply is one
let expected = qty // We expect to get that value back
// ACT
let actual = UnitQuantity.create qty
// ASSERT
// Check if we have an Ok or an Error
match actual with
| Ok unitQuantity ->
// If Ok, check the value is what we expect
let innerValue = UnitQuantity.value unitQuantity
Assert.Equal(innerValue, expected)
// If Error raise an AssertException to fail the test
| Error errorMessage ->
let error = sprintf "Expected Ok, was Error(%s)." errorMessage
Assert.True(false, error) // Force an assertion failure with our error message
Run Code Online (Sandbox Code Playgroud)
请注意该UnitQuantity.value
方法,它是一个简单的解包函数,您可以将其添加到模块的末尾,UnitQuantity
该函数将返回int
值,以便您可以轻松比较它
let value (UnitQuantity e) = e
Run Code Online (Sandbox Code Playgroud)
如果你想测试一个option
类型,它会非常相似,使用像这样的匹配语句
match actual with
| Some value ->
// Do your assertions here
()
| None ->
// Do your assertions here
()
Run Code Online (Sandbox Code Playgroud)