0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2023-03-19

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
    }
}


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?