サルだとわからん-やさしいSwift単体テスト 編集途中!

やさしいSwift単体テスト~テスト可能なクラス設計・後編~ - Qiita

そもそもテストとは

ざっくりいうと

入力値、引数を渡して、期待する結果も入力する。 そのとおり出力されるかをチェックする。

ポイント!

UIつまり、ビューと接続しているところは単体テストできない。必ずビューに依存しているので。

例えると結婚と筋肉トレーニングである。

あと1年以内に結婚すると決めたとしても、相手がいることなので、必ずしも結婚できるとは限らない。
そのようなものはテストできない。 しかし、筋肉トレーニングは、毎日時間を決めてやれば、必ず筋肉はつく。程度の差はあるが、、 同じように、画面と接続していると、StoryBoardが裏で(プログラムの影響範囲外)で動くので、基本単体テストはできない。 自動化して、できるようにすることもある。ここでは触れません。

だからMVVCの理論がある。

f:id:happy_teeth_ago:20190427124011p:plain
MVVMモデル
上記で赤のviewとつながっているところは、はテストできない しかし、緑と青のModel,Viewmodelはテスト可能。

ポイント

まずコードをViewとロジックで明確に切り分ける必要がある。

例 この関数をテストするとします。

まずこの関数はViewControllerに記載されているので、ViewControllerに依存しない、別クラスを作成します。

   func HogeHoge(_ y : Int) {
        do{
            let goals = try self.viewContext.fetch(goalQuery)
            if y == 0 {
                for goal in goals {
                    goalList.insert(goal, at: 0)
                    if goalList[0].image != nil {
                        let buttonImage = UIImage(data: goalList[0].image as! Data)
                        goButton.setImage(buttonImage, for: .normal)
                    }
//ここが良くない。Viewと接続している。ここを分離する。
                    self.mokuhyoLabel.text = goalList[0].name
                    self.dateLabel.text = goalList[0].date! + "までに"
//これはメンバに返却しているだけなので、OK
                    self.x = 1
                }
            }
            
        }catch{
            print("フェッチできない")
        }
    }

修正後 詳細はコメントをみてください

class HogeHoge_test {

//Viewに返す値を作成するためにstructを作成
//返却値を宣言
    struct ReturnValue{
        var x:Int
        var goButton:UIImage
        var mokuhyouLabel: String
        var dateLabel: String
        
    }
    
    let goalQuery: NSFetchRequest<Goal> = Goal.fetchRequest()
    var viewContext = (UIApplication.shared.delegate as!
        AppDelegate).persistentContainer.viewContext
    //他で追加していないので
    var goalList: [Goal] = []
    
    func getCoreData2(_ y : Int)-> ReturnValue? {
        do{
            let goals = try self.viewContext.fetch(goalQuery)
            if y == 0 {
                for goal in goals {
                    goalList.insert(goal, at: 0)
                }
                if goalList[0].image != nil {
                    let buttonImage = UIImage(data: goalList[0].image as! Data)
                  let returnValue =  ReturnValue.init(x: 1, goButton: buttonImage!, mokuhyouLabel: goalList[0].name!, dateLabel: goalList[0].date!)
                    //                        goButton.setImage(buttonImage, for: .normal)
                    //                    self.mokuhyoLabel.text = goalList[0].name
                    //                    self.dateLabel.text = goalList[0].date! + "までに"
                    //self.x = 1
                    return returnValue
                }
                return nil
            }