【问题标题】:property-based-test for simple object validation用于简单对象验证的基于属性的测试
【发布时间】:2015-12-28 07:31:02
【问题描述】:

考虑这个简单的例子:

  • 有一个Person 对象
  • 它必须具有以下之一:FirstNameLastName(或两者,但必须有一个)
  • 它必须有一个有效的Age(整数,介于 0 和 150 之间)

您将如何对这个简单的案例进行基于属性的测试?

【问题讨论】:

    标签: unit-testing testing language-agnostic property-based-testing


    【解决方案1】:

    我认为您无法以与语言无关的方式有意义地回答这个问题,因为整体设计方法将完全取决于相关语言的功能。

    例如,在具有强静态类型和求和类型的语言中,上述大多数需求都可以使用类型系统以声明方式建模。这是一个 F# 示例:

    type Name =
    | FirstName of string
    | LastName of string
    | FullName of string * string
    

    Name 类型只能包含名字或姓氏,或两者都包含。无法创建不符合要求的值。

    可以通过将类型放在单独的模块中来隐藏以下 Age 类型的 case 构造函数。如果该模块仅导出下面的toAge(和getAge)函数,则创建Age 值的唯一方法是调用toAge

    type Age = Age of int
    
    let toAge x =
        if 0 <= x && x <= 150
        then Some (Age x)
        else None
    
    let getAge (Age x) = x
    

    使用这些辅助类型,您现在可以定义Person 类型:

    type Person = { Name : Name; Age : Age }
    

    大多数需求都嵌入在类型系统中。您无法创建Person 类型的无效值

    toAge 函数中包含唯一可能失败的行为,因此这是唯一可以有意义地接受基于属性的测试的行为。下面是一个使用 FsCheck 的例子:

    open System
    open FsCheck
    open FsCheck.Xunit
    open Swensen.Unquote
    
    [<Property(QuietOnSuccess = true)>]
    let ``Value in valid age range can be turned into Age value`` () =
        Prop.forAll (Gen.choose(0, 150) |> Arb.fromGen) (fun i ->
            let actual = toAge i
            test <@ actual |> Option.map getAge |> Option.exists ((=) i) @>)
    
    [<Property(QuietOnSuccess = true)>]
    let ``Value in invalid age range can't be turned into Age value`` () =
        let tooLow = Gen.choose(Int32.MinValue, -1)
        let tooHigh = Gen.choose(151, Int32.MaxValue)
        let invalid = Gen.oneof [tooLow; tooHigh] |> Arb.fromGen
        Prop.forAll invalid (fun i ->
    
            let actual = toAge i
    
            test <@ actual |> Option.isNone @>)
    

    如您所知,它测试两种情况:有效输入值和无效输入值。它通过为每种情况定义生成器,然后验证 actual 值来实现这一点。

    【讨论】:

    • 谢谢马克,我不知道 F#,但似乎你可以创建一个无效的人也传递空字符串,对吗?我想在这种情况下,您会像检查年龄范围一样检查它们的长度,对吧?
    • 正确,如果空字符串无效(这是合理的),那么方法将与年龄相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多