SwiftでTDD写経 第10章 テストに聞いてみる

timesメソッドはかなり似ているが、完全に一致するところまではたどり着いていない。

では例えば、2つのFactory Methodをインライン化したらどうなるだろうか?

```playground.swift
///Dollar子クラス
class Dollar:Money {
    override init(_ amount:Int,_ currency:String){
        super.init(_ :amount , _ :currency)
        self.amount = amount
        self.currency = currency
    }
    override func times(_ multiplire:Int)  -> Dollar{
        return Dollar(amount * multiplire, "USD")
    }
}
```

```playground.swift
///Franc子クラス
class Franc:Money {
    override init(_ amount:Int, _ currency:String){
        super.init(_ :amount , _ :currency)
        self.amount = amount
        self.currency = currency
    }
    override func times(_ multiplire:Int)  -> Franc{
        return Franc(amount * multiplire, "CHF")
    }
}

```

でFranCクラスでは、インスタンス変数currencyは常にCHFであることがわかっている。
つまり次のように書ける。

```playground.swift
///Franc子クラス
class Franc:Money {
    override init(_ amount:Int, _ currency:String){
        super.init(_ :amount , _ :currency)
        self.amount = amount
        self.currency = currency
    }
    override func times(_ multiplire:Int)  -> Franc{
        return Franc(amount * multiplire, currency)
    }
}

```

Dollarにも適用できる。

```playground.swift
///Dollar子クラス
class Dollar:Money {
    override init(_ amount:Int,_ currency:String){
        super.init(_ :amount , _ :currency)
        self.amount = amount
        self.currency = currency
    }
    override func times(_ multiplire:Int)  -> Dollar{
        return Dollar(amount * multiplire, currency)
    }
}
```


と,ここからは考えるのではなく、コンピュータに聞いてしまおうという流れ。
優秀なソフトウェアエンジニアが10分考えて出す結論を、コンピュータなら15秒で出してしまう。
テストがなければ選択の余地はなく、慎重に検討せざるをえない。テストがあれば、試したほうが早いかどうかを選択できる。さっさとコンピュータに聞けばいい場合もある。


```playground.swift

///Dollar子クラス
class Dollar:Money {
    override init(_ amount:Int,_ currency:String){
        super.init(_ :amount , _ :currency)
        self._amount = amount
        self._currency = currency
    }
    
    override func times(_ multiplire:Int) -> Money{
        return Money(_amount * multiplire, _currency)
    }
}

//Franc子クラス
class Franc:Money {
    override init(_ amount:Int, _ currency:String){
        super.init(_ :amount , _ :currency)
        self._amount = amount
        self._currency = currency
    }

    override func times(_ multiplire:Int) -> Money{
        return Money(_amount * multiplire, _currency)
    }
}

```

ここまでくると、times methodは共通化できたといっていい。
これを親クラスに移す。

で、さらなる問題はFranc型とMoney型の区別は本当に必要だろうか?という話。
本当に調べるべきは通貨が等しいかどうかであって、クラスが同じかどうかではない。

通貨の比較テストを書こう。

```playground.swift
class MoneyTest{

.....

 func testCurrency(){
        assert("USD" == Money.dollar(1).currency())
        assert("CHF" == Money.franc(1).currency())
    }
    
    func testDifferentClassEquaﾕﾕty() {
        assert(Money(10, "CHF") == Money(10, "CHF"))
    }

.....

```


```playground.swift

///親クラス
class Money :Equatable{
    var _amount:Int
    var _currency:String
    init(_ amount:Int,_ currency:String){
        self._amount = amount
        self._currency = currency
    }
    
    static func == (lhs: Money, rhs: Money) -> Bool {
        return lhs._amount == rhs._amount &&
        lhs.currency() == rhs.currency()
    }

    func times(_ multiplire:Int) -> Money{
        return Money(_amount * multiplire, _currency)
    }
    
    func currency() -> String{
        return _currency
    }
    
    func toString() -> String{
        return _amount.description + " " + _currency
    }
    
    static func dollar(_ amount:Int) -> Money{
        return Dollar(amount,"USD")
    }
    
    static func franc(_ amount:Int) -> Money{
        return Franc(amount,"CHF")
    }
}


```


ぜんぶのこーど

```playground.swift
var moneytest = MoneyTest()

moneytest.testMultiplication()
moneytest.testEquality()
moneytest.testFrancMultiplication()
moneytest.testCurrency()
moneytest.testDifferentClassEquaﾕﾕty()

class MoneyTest{
    init(){}
    
    func testMultiplication(){
        var five:Money = Money.dollar(5)
        assert(Money.dollar(10) == five.times(2))
        assert(Money.dollar(15) == five.times(3))
    }
    
    func testEquality(){
        assert(Money.dollar(5) == Money.dollar(5))
        assert(Money.dollar(6) == Money.dollar(6))
        assert(Money.franc(5) == Money.franc(5))
        assert(Money.franc(6) == Money.franc(6))
        assert(Money.franc(6) != Money.franc(3))
        assert(Money.franc(6) == Money.dollar(6))
    }
    
    func testFrancMultiplication(){
        var five = Money.franc(5)
        assert(Money.franc(10) == five.times(2))
        assert(Money.franc(15) == five.times(3))
    }
    
    func testCurrency(){
        assert("USD" == Money.dollar(1).currency())
        assert("CHF" == Money.franc(1).currency())
    }
    
    func testDifferentClassEquaﾕﾕty() {
        assert(Money(10, "CHF") == Money(10, "CHF"))
    }
}
///親クラス
class Money :Equatable{
    var _amount:Int
    var _currency:String
    init(_ amount:Int,_ currency:String){
        self._amount = amount
        self._currency = currency
    }
    
    static func == (lhs: Money, rhs: Money) -> Bool {
        print(lhs.currency())
        print(rhs.currency())
        return lhs._amount == rhs._amount &&
        lhs.currency() == rhs.currency()
    }
    
    func currency() -> String{
        return _currency
    }
    
    func toString() -> String{
        return _amount.description + " " + _currency
    }
    
    func times(_ multiplire:Int)  -> Money{
        return Money(_amount * multiplire, _currency)
    }
    
    static func dollar(_ amount:Int) -> Money{
        return Dollar(amount,"USD")
    }
    
    static func franc(_ amount:Int) -> Money{
        return Franc(amount,"CHF")
    }
}

///Dollar子クラス
class Dollar:Money {
    override init(_ amount:Int,_ currency:String){
        super.init(_ :amount , _ :currency)
        self._amount = amount
        self._currency = currency
    }
}

//Franc子クラス
class Franc:Money {
    override init(_ amount:Int, _ currency:String){
        super.init(_ :amount , _ :currency)
        self._amount = amount
        self._currency = currency
    }
}


```