iT邦幫忙

2023 iThome 鐵人賽

DAY 10
1
Mobile Development

在 iOS 專案上加上 Unit testing - 因為 You need testing系列 第 10

D10 - 在 iOS 專案加上測試-You need testing {台股小工具 app-交易紀錄物件宣告}

  • 分享至 

  • xImage
  •  

開新檔案寫測試

Xcode 在排版上最適合邊寫測試邊開發的方法,就是左右併排。一邊寫測試程式碼,另一邊寫程式實作。

開 StockTradingRecord 檔案與 StockTradingRecordTests 測試檔案,開好後將多餘的模版程式碼刪除掉,大概會長這樣。然後,我們就可以開始寫測試了。

https://ithelp.ithome.com.tw/upload/images/20230921/201406223AhTS8lDqf.png

在 test 那邊加上一個 func,注意 func 要有 test 前綴才能被 XCTest 認知到這是 test func

func testStockTradingRecordInit() {  
    }

StockTradingRecord 物件的宣告

從前面的 wireframe 來看,我們會需要 stockID, stockName, tradingSide, tradingShares, tradingAmount。這個物件的宣告可以先這樣子寫。

extension StockTradingRecord {
    
    enum TradingSide {
        case buy
        case sell
    }
}

struct StockTradingRecord {
    
    let stockID: String
    let stockName: String
    let tradingSide: TradingSide
    
    /// 成交股數
    let tradingShares: Int
    
    /// 成交金額
    let tradingAmount: Int
}

測試 StockTradingRecord 物件

第一步,要讓測試 failed,用來確定錯誤的時候 unit testing 可以正確的告訴你錯誤

func testStockTradingRecordInit() {
        
let model = StockTradingRecord(stockID: "1101", stockName: "台泥", tradingSide: .buy, tradingShares: 1000, tradingAmount: 35000)
        /// 讓 test failed
        XCTAssertEqual(model.stockID, "1102")
    }

然後,確認 test failed 後,把 test 改成可以通過的狀態

func testStockTradingRecordInit() {
        
        let model = StockTradingRecord(stockID: "1101",
                                       stockName: "台泥",
                                       tradingSide: .buy,
                                       tradingShares: 1000,
                                       tradingAmount: 35000)
        
        XCTAssertEqual(model.stockID, "1101")
        XCTAssertEqual(model.stockName, "台泥")
        XCTAssertEqual(model.tradingSide, .buy)
        XCTAssertEqual(model.tradingShares, 1000)
        XCTAssertEqual(model.tradingAmount, 35000)
    }

Voila! 資料 Model 的測試就完成了。

https://ithelp.ithome.com.tw/upload/images/20230921/201406225KqWNbLClz.png

但從 StockTradingRecord 的宣告來看, tradingShares 和 tradingAmount 是可以塞入負數的。所以如果寫 init 帶入負數的 data model testing,是會通過的。

func testStockTradingRecordSell() {
        
        let model = StockTradingRecord(stockID: "1101",
                                       stockName: "台泥",
                                       tradingSide: .buy,
                                       tradingShares: -2000,
                                       tradingAmount: -70000)
        
        XCTAssertEqual(model.stockID, "1101")
        XCTAssertEqual(model.stockName, "台泥")
        XCTAssertEqual(model.tradingSide, .buy)
        XCTAssertEqual(model.tradingShares, -2000)
        XCTAssertEqual(model.tradingAmount, -70000)
    }

好,問題來了,tradingShares, tradingAmount 可不可以輸入負數?如果不可以,那應該把 tradingShares 和 tradingAmount 設定成 UInt 嗎?

我們先把宣告改成 UInt 並跑一次測試

https://ithelp.ithome.com.tw/upload/images/20230921/20140622QanBg3DPoi.png

當我們宣告成 UInt 的時候 Unit testing 是沒辦法執行,因為 Swift 是強型別語言,當參數的型別不合格的時候,在 compile time 就會停下來,Unit testing 本身也是一個 target,所以在跑 unit testing 時,就會 build failed。

那…這個 Model 在 tradingShares 和 tradingAmount 該使用哪個型別?

以買進股票為例,帳戶的持股數會增加,金流方向是從約定帳戶匯出到券商帳戶。所以如果開發的時候定義,約定帳戶的金額增加的動作為 +,金額減少的動作為 -。用 Int 就合理。

但一筆交易,會在[買進]/[賣出] 中二者擇一 (除權息的紀錄先會是其他 feature),開發時然可以決定[買進]/[賣出]的行為本身來決定金流和股數變化的方向。

所以在這邊,並沒辦法指出唯一解法,在實務上的設計,比較好的做法是將 spec 列出,程式邏輯列出,讓不同的平台(iOS, Android, Web, 後端) 都用同一個邏輯,然後各自使用自己端的語言實作。

本次鐵人賽的策略

因這個專案的開發者只有我,所以並沒有第二個人需要討論,這裡的策略是先讓 model 的 tradingShares, tradingAmount 設成 Int,並寫下 Unit testing。在有 Unit testing 的狀況下,即使未來我需要修改,我仍然可以對修改具有信心。

struct StockTradingRecord {
    
    let stockID: String
    let stockName: String
    let tradingSide: TradingSide
    
    /// 成交股數
    let tradingShares: Int
    
    /// 成交金額
    let tradingAmount: Int
}
func testStockTradingRecordSell() {
        
        let model = StockTradingRecord(stockID: "1101",
                                       stockName: "台泥",
                                       tradingSide: .buy,
                                       tradingShares: -2000,
                                       tradingAmount: -70000)
        
        XCTAssertEqual(model.stockID, "1101")
        XCTAssertEqual(model.stockName, "台泥")
        XCTAssertEqual(model.tradingSide, .buy)
        XCTAssertEqual(model.tradingShares, -2000)
        XCTAssertEqual(model.tradingAmount, -70000)
    }

上一篇
D9 - 在 iOS 專案加上測試-You need testing {台股小工具 app-交易紀錄 wireframe}
下一篇
D11 - 在 iOS 專案加上測試-You need testing {台股小工具 app-交易紀錄頁面}
系列文
在 iOS 專案上加上 Unit testing - 因為 You need testing32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言