私はF#を学ぼうとしていて、いくつかの簡単なクラスで遊んでいますが、これらは期待どおりに動作していません。
私はいくつかの単純な基本を誤解しているに違いありません。この質問が基本的すぎる場合はお詫びしますが、助けていただければ幸いです。
とにかく、私は初めてテスト駆動開発アプローチを適用しましたが、今ではこれの利点をよりよく理解しています。
次のソースコードの調査:
- ユーティリティ関数(optionIntTo_s)を定義します。
- クラスTUnitTesterを定義します-その目的はユニットテストを支援することです。
- 実験的なクラスTOrderItemを定義します。これは可変オプションフィールドのfquantityをラップします(SQL nullまたは整数値を表します)。
- TOrderItemオブジェクトの配列をラップする別の実験クラスTOrderItemsを定義します。
- クラスTOrderItemで4つのテストを実行します。これらはすべて期待どおりに機能します。
- クラスTOrderItemsに対してさらに10個のテストを実行します。これらのうち2つは失敗します(合計14回のテストのうち6回と8回が実施されました)。
これらの失敗したテストを説明するのに助けをいただければ幸いです。
これがソースコードで、その後私が得た出力は次のとおりです。
//-----------------------------------------------------------------------------------------------------------------
// 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コンパイラビルド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