F#Mutable Array&单元测试中不符合预期的基本类

时间:2012-07-06 09:41:29

标签: arrays class f# mutable

我正在尝试学习F#并开始使用几个简单的类,但这些并不像预期的那样。

我必须误解一些简单的基础。如果这个问题太基础,请道歉,但任何帮助都会受到赞赏。

无论如何,我第一次采用了测试驱动的开发方法,现在我更加了解这一点的好处。

以下源代码探索:

  1. 定义效用函数(optionIntTo_s)。
  2. 定义类TUnitTester - 其目的是协助进行单元测试。
  3. 定义实验类TOrderItem - 它包装一个可变选项字段fquantity(表示一个SQL null else整数值)。
  4. 定义另一个实验类TOrderItems - 它包装一组TOrderItem对象。
  5. 对TOrderItem类进行4次测试;这些都按预期工作。
  6. 对TOrderItem类进行另外10次测试;其中两个失败了(总共进行了14次中的6次和8次测试)!
  7. 任何帮助解释这些失败的测试都将不胜感激。

    这是源代码,然后是我得到的输出:

    //-----------------------------------------------------------------------------------------------------------------
    // Utility Funcions
    //-----------------------------------------------------------------------------------------------------------------
    let optionIntTo_s(aValue : option<int>) = 
        match aValue with
        | None    -> "null"
        | Some(_) -> sprintf "%d" (Option.get(aValue))
    
    
    //-----------------------------------------------------------------------------------------------------------------
    // Class TUnitTester
    //-----------------------------------------------------------------------------------------------------------------
    type TUnitTester = class
        //----------------------------------
        // Field Definitions
        //----------------------------------
        val mutable ftestCount : int
        val mutable fsuccessCount : int
    
    
        //----------------------------------
        // Constructors
        //----------------------------------
        new ()  =
            {ftestCount = 0;
             fsuccessCount = 0}
    
    
        //----------------------------------
        // Methods
        //----------------------------------
        member this.assertEqual(aTestValue, aExpectation, aDescription) = 
            this.ftestCount <- this.ftestCount + 1
    
            if (aTestValue = aExpectation) then
                this.fsuccessCount <- this.fsuccessCount + 1
                printfn "Test %d: assertEqual succeeded: expected %A: got %A; %s" this.ftestCount aExpectation aTestValue aDescription
            else
                printfn "Test %d: assertEqual failed:    expected %A: got %A; %s" this.ftestCount aExpectation aTestValue aDescription
    
    
        member this.assertFalse(aDescription, aTestValue : bool) = 
            this.ftestCount <- this.ftestCount + 1
    
            if (aTestValue) then
                this.fsuccessCount <- this.fsuccessCount + 1
                printfn "assertFalse succeeded: expected false: got false; %s" aDescription
            else
                printfn "assertFalse failed:    expected false: got true;  %s" aDescription
    
    
        member this.assertTrue(aDescription, aTestValue : bool) =
            this.ftestCount <- this.ftestCount + 1
    
            if (aTestValue) then
                this.fsuccessCount <- this.fsuccessCount + 1
                printfn "assertTrue  succeeded: expected true: got true;  %s" aDescription
            else
                printfn "assertTrue  failed:    expected true: got false; %s" aDescription
    
    
        member this.printStatistics() =
            printfn "total tests = %d; successes = %d; failures = %d"  this.ftestCount this.fsuccessCount (this.ftestCount - this.fsuccessCount)
    end;;
    
    
    //-----------------------------------------------------------------------------------------------------------------
    // Class TOrderItem
    //    Ref: "F# option cheat sheet" - http://missingfaktor.blogspot.com.au/2012/02/f-option-cheat-sheet.html
    //-----------------------------------------------------------------------------------------------------------------
    type TOrderItem = class
        //----------------------------------
        // Field Definitions
        //----------------------------------
        val mutable fquantity : option<int>
    
    
        //----------------------------------
        // Properties
        //----------------------------------
        member this.quantity  with get() = Option.get(this.fquantity) and 
                                   set(aValue : int) = this.fquantity <- Some(aValue)
    
        member this.isNull    with get() = Option.isNone(this.fquantity)
        member this.isNotNull with get() = Option.isSome(this.fquantity)
    
    
        //----------------------------------
        // Constructors
        //----------------------------------
        new ()  =
            {fquantity = None;}
    
        new (aValue : int)  =
            {fquantity = Some(aValue);}
    
    
        //----------------------------------
        // Methods
        //----------------------------------
        member this.to_s() = optionIntTo_s(this.fquantity)
    end;;
    
    
    
    //-----------------------------------------------------------------------------------------------------------------
    // Class TOrderItems
    //-----------------------------------------------------------------------------------------------------------------
    type TOrderItems = class
        //----------------------------------
        // Field Definitions
        //----------------------------------
        val fOrderItems : TOrderItem []
    
    
        //----------------------------------
        // Properties
        //----------------------------------
        member this.orderItems with get() = this.fOrderItems
    
    
        //----------------------------------
        // Constructors
        //----------------------------------
        new (aLength : int)  =
            { fOrderItems = Array.create aLength (TOrderItem())}
    
    
        //----------------------------------
        // Methods
        //----------------------------------
        member this.Item i = this.fOrderItems.[i]     //Translates to the operator this.[i]
    
        member this.setAll(aValue : int) = 
            for i = 0 to (Array.length this.fOrderItems) - 1 do
                this.fOrderItems.[i].quantity <- aValue
    
        member this.setFromCombination(aScale1, aScale2, (aOrderItems1 : TOrderItems), (aOrderItems2 : TOrderItems)) =
            for i = 0 to (Array.length this.fOrderItems) - 1 do
                this.fOrderItems.[i].quantity <- aScale1 * aOrderItems1.[i].quantity + aScale2 * aOrderItems2.[i].quantity
    
        member this.setFromDifference((aOrderItems1 : TOrderItems), (aOrderItems2 : TOrderItems)) =
            this.setFromCombination(1, -1, aOrderItems1, aOrderItems2)
    
        member this.setFromSum((aOrderItems1 : TOrderItems), (aOrderItems2 : TOrderItems)) =
            this.setFromCombination(1, 1, aOrderItems1, aOrderItems2)
    
        member this.setItem i (aValue : int) =         //TODO NUKE THIS METHOD LATER....
            this.fOrderItems.[i].quantity <- aValue
    
        member this.to_s() = 
            Array.fold (fun (accumulator : string) (item : TOrderItem) -> accumulator + item.to_s() + "; ") "" this.fOrderItems
            |> (fun (x) -> "[| " + x + "|]")
    end;;
    
    
    //-----------------------------------------------------------------------------------------------------------------
    // Test Classes TOrderItem and TOrderItems
    //    (A) Create unit tester instance.
    //-----------------------------------------------------------------------------------------------------------------
    let myTester = TUnitTester()
    
    
    //-----------------------------------------------------------------------------------------------------------------
    //    (B) Test Class TOrderItem
    //-----------------------------------------------------------------------------------------------------------------
    let myOrderItem = TOrderItem()
    myTester.assertEqual(myOrderItem.to_s(), "null", "myOrderItem.to_s()")        //Test 1 - OK
    
    myOrderItem.quantity <- 8000
    myTester.assertEqual(myOrderItem.quantity, 8000, "myOrderItem.quantity")      //Test 2 - OK
    
    myOrderItem.quantity <- 9000
    myTester.assertEqual(myOrderItem.quantity, 9000, "myOrderItem.quantity")      //Test 3 - OK
    myTester.assertEqual(myOrderItem.to_s(), "9000", "myOrderItem.to_s()")        //Test 4 - OK
    
    
    //-----------------------------------------------------------------------------------------------------------------
    //    (C) Test Class TOrderItems
    //-----------------------------------------------------------------------------------------------------------------
    let myOrderItems = TOrderItems(4)
    myTester.assertEqual(myOrderItems.to_s(), "[| null; null; null; null; |]", "myOrderItems.to_s()")  //Test 5 - OK
    
    myOrderItems.[2].quantity <- 1000
    myTester.assertEqual(myOrderItems.to_s(), "[| null; null; 1000; null; |]", "myOrderItems.to_s()")  //Test 6 - Fails!
    
    myOrderItems.setAll 5000
    myTester.assertEqual(myOrderItems.[2].quantity, 5000, "myOrderItems.[2].quantity")                 //Test 7 - OK
    
    myOrderItems.setItem 1 9999
    myTester.assertEqual(myOrderItems.[0].quantity , 5000, "myOrderItems.[0].quantity")                //Test 8 - Fails!
    myTester.assertEqual(myOrderItems.[1].quantity , 9999, "myOrderItems.[1].quantity")                //Test 9 - OK
    
    
    let myOrderItems1 = TOrderItems(4)
    let myOrderItems2 = TOrderItems(4)
    let myOrderItems3 = TOrderItems(4)
    let myOrderItems4 = TOrderItems(4)
    let myOrderItems5 = TOrderItems(4)
    
    myOrderItems1.setAll 5000
    myOrderItems2.setAll 4000
    
    myTester.assertEqual(myOrderItems1.to_s(), "[| 5000; 5000; 5000; 5000; |]", "myOrderItems1.to_s()")      //Test 10 - OK
    myTester.assertEqual(myOrderItems2.to_s(), "[| 4000; 4000; 4000; 4000; |]", "myOrderItems2.to_s()")      //Test 11 - OK
    
    
    myOrderItems3.setFromCombination(2, 3, myOrderItems1, myOrderItems2)
    myTester.assertEqual(myOrderItems3.to_s(), "[| 22000; 22000; 22000; 22000; |]", "myOrderItems3.to_s()")  //Test 12 - OK
    
    
    myOrderItems4.setFromSum(myOrderItems1, myOrderItems2)
    myTester.assertEqual(myOrderItems4.to_s(), "[| 9000; 9000; 9000; 9000; |]", "myOrderItems4.to_s()")      //Test 13 - OK
    
    
    myOrderItems5.setFromDifference(myOrderItems1, myOrderItems2)
    myTester.assertEqual(myOrderItems5.to_s(), "[| 1000; 1000; 1000; 1000; |]", "myOrderItems5.to_s()")      //Test 14 - OK
    
    
    //-----------------------------------------------------------------------------------------------------------------
    //    (D) Report test statistics.
    //-----------------------------------------------------------------------------------------------------------------
    myTester.printStatistics()
    

    最后,这是我在MAC OS X上的mono下从Microsoft(R)F#2.0 Compiler build 2.0.0.0获得的输出如下:

    Microsoft (R) F# 2.0 Compiler build 2.0.0.0
    Copyright (c) Microsoft Corporation. All Rights Reserved.
    Test 1: assertEqual succeeded: expected "null": got "null"; myOrderItem.to_s()
    Test 2: assertEqual succeeded: expected 8000: got 8000; myOrderItem.quantity
    Test 3: assertEqual succeeded: expected 9000: got 9000; myOrderItem.quantity
    Test 4: assertEqual succeeded: expected "9000": got "9000"; myOrderItem.to_s()
    Test 5: assertEqual succeeded: expected "[| null; null; null; null; |]": got "[| null; null; null; null; |]"; myOrderItems.to_s()
    Test 6: assertEqual failed:    expected "[| null; null; 1000; null; |]": got "[| 1000; 1000; 1000; 1000; |]"; myOrderItems.to_s()
    Test 7: assertEqual succeeded: expected 5000: got 5000; myOrderItems.[2].quantity
    Test 8: assertEqual failed:    expected 5000: got 9999; myOrderItems.[0].quantity
    Test 9: assertEqual succeeded: expected 9999: got 9999; myOrderItems.[1].quantity
    Test 10: assertEqual succeeded: expected "[| 5000; 5000; 5000; 5000; |]": got "[| 5000; 5000; 5000; 5000; |]"; myOrderItems1.to_s()
    Test 11: assertEqual succeeded: expected "[| 4000; 4000; 4000; 4000; |]": got "[| 4000; 4000; 4000; 4000; |]"; myOrderItems2.to_s()
    Test 12: assertEqual succeeded: expected "[| 22000; 22000; 22000; 22000; |]": got "[| 22000; 22000; 22000; 22000; |]"; myOrderItems3.to_s()
    Test 13: assertEqual succeeded: expected "[| 9000; 9000; 9000; 9000; |]": got "[| 9000; 9000; 9000; 9000; |]"; myOrderItems4.to_s()
    Test 14: assertEqual succeeded: expected "[| 1000; 1000; 1000; 1000; |]": got "[| 1000; 1000; 1000; 1000; |]"; myOrderItems5.to_s()
    total tests = 14; successes = 12; failures = 2
    

1 个答案:

答案 0 :(得分:4)

更改

Array.create aLength (TOrderItem())

Array.init aLength (fun t -> TOrderItem())

第一个创建一个包含许多副本的数组 - 它实际上是为int设计的,第二个是你希望它做的

此外,将来可以使用问题发布更少的代码以简化