티스토리 뷰

공부

Code Coverage

Zedd0202 2020. 10. 7. 22:07
반응형

 

안녕하세요 :) Zedd입니다.

오늘은 Code Coverage를 알아보는 방법에 대해서 공부해보겠습니다.

 

# Code Coverage?

Code Coverage는 테스트의 가치를 측정하는 도구.

(Code coverage is a tool to measure the value of your tests.)

출처 : 애플 문서

 

# Code Coverage 활성화

Edit Scheme의 Test > Options에 가시면 

Code Coverage 모으도록 체크할 수 있습니다. allTargets으로 할 수도 있고,

some Target으로 바꾸면, 

특정 Target을 선택할 수도 있습니다.

저는 이렇게만 해줄게요. 

그런 다음, 테스트를 돌리면 Report Navigator에

이렇게 Code Coverage가 생기게 됩니다.

이렇게 Code Coverage를 확인 할 수 있습니다.

메소드별로 Coverage를 확인 할 수 있습니다. 

각 파일이나 메소드를 더블클릭하면 이동하게 됩니다.

이동해서 오른쪽을 잘..보면

이렇게 초록, 빨강, 스트라이프?;;이런식으로 나오는 것을 볼 수 있는데, 

초록은 cover된거, 빨강은 cover안된거,

스트라이프는 초록인 부분도 있고 빨강인 부분도 있는데..

부분적으로 cover된 영역을 의미하는 것 같습니다..!!!

 

# 아니...나 아무것도 안했는데 Code Coverage가 왜이렇게 높아..?

갓 만든 프로젝트이며 테스트 코드는 기본으로 만들어지는 그 테스트 파일밖에 없습니다. 

즉 아무것도 테스트하고 있지 않습니다. 

근데 100%나오는건 뭐고....뭘까요 이거??

 

예를 하나 들어봅시다.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
    }
}

ViewController.swift코드는 이게 다입니다. 근데 

viewDidLoad()의 Code Coverage는 100%로 나와있죠.

1. 테스트를 실행합니다.

2. Xcode는 앱의 인스턴스를 생성합니다 => 시뮬레이터에서 앱이 실행됩니다.

3. AppDelegate, SceneDelegate메소드들이 실행됩니다. 

4. 현재 저의 첫 화면은 ViewController입니다. 

5. ViewController의 viewDidLoad가 불리게 됩니다.

6. viewDidLoad가 실행되었으므로 해당 코드가 cover된 것으로 보고됩니다.

만약 ViewController에서 SecondViewController로 가는 버튼이 있다고 생각해봅시다. 

하지만 지금 UITest가 있는것도 아니고...SecondViewController에 대한 테스트도 하나도 없는 상태입니다.

이 상태로 Code Coverage를 측정하면,

SecondViewController의 viewDidLoad()는 실행되지 않았음 == cover된 것으로 판단 x == Code Coverage 0%.

그래서 다시 이 그림을 보면 100%인 애들은 왜 100%인지 알 수 있죠. 

즉 테스트 코드가 하나도 없더라도, 실행된거는 커버치는겁니다. 

 

# 아 이거 Code Coverage쳐지는거 개쌉오바

해결해보겠습니다.

1. main.swift생성.

제 앱 Target에 생성해주세요!!!!

2. TestingAppDelegate, TestingSceneDelegate 생성.

UnitTest Target에 생성해주세요!!!

TestingAppDelegate.swift

TestingSceneDelegate.swift

3. 앱 타겟에 있는 AppDelegate의 main진입점 삭제. 

앱 타겟에 있는 AppDelegate의 @mian또는 @UIApplicationMain을 지워주세요.

이제 main.swift가 시작점이 되게 됩니다. 

 

이제 테스트를 실행하면..!!

이렇게 AppDeleage, SceneDelegate, 첫화면인 ViewController까지 0%로 나오게 됩니다. 

 

# Q&A

1. for sceneSession in application.openSessions

TestingAppDelegate의

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        for sceneSession in application.openSessions {
            application.perform(Selector(("_removeSessionFromSessionSet:")), with: sceneSession)
        }
        
        return true
    }

여기서 저 for문...이 뭐지...?? 의문이 드실 수 있을 것 같은데요, 

위 메소드에서 그냥 return true를 하면 TestingSceneDelegate가 불리는게 아니라 앱 타겟의 SceneDelegate가 불리게 되더라구요.

==> SceneDelegate의 Code Coverage가 0%로 나오지 않음.

여기를 보고 참고했습니다. 참고로 위 문법은 private api라고 하니...조심해서 써야 할 것 같습니다. 

하는 방법 다 알려주고 할 말은 아닌 것 같지만..

AppDelegate랑 SceneDelegate를 Mocking까지 하는건...좀...별로다 이게 아니라 

그냥 뭐 Code Coverage에 같이 나오면 어때?!?!? 이느낌..ㅎ!!!

 

2. UITest?

UITest역시 Test이니 Code Coverage가 나오게 됩니다. 

위에서 만든 코드들은 Unit Test Target쪽에 만든 코드들이라 UITest때는 전혀 문제없구요. 

다들 아시다시피 UITest는 앱(XCUIApplication)을 실행하잖아요?

그래서 

이렇게 기존의 AppDelegate, SceneDelegate가 불리게 됩니다. 

 

3. Code Coverage와 성능

애플 Code Coverage문서에 따르면 Code coverage 데이터 수집은 성능저하를 초래한다고 나와있습니다. 

근데 뭐 엄청 크리티컬 하진 않을 듯

 

4. Code Coverage로 얻을 수 있는 것들.

- 테스트를 실행 할 때 실제로 어떤 코드가 실행되는지

- 모든 코드의 정확성과 성능을 확인하기 위해 충분한 테스트를 설계했는지.

- 코드의 어떤 부분이 테스트되지 않았는지

등등을 알 수 있습니다.

저는 살짝의 자괴감도 얻었네요 하하

뭐 이제 올라갈 일만 남았다는거니까요 하하

하하~~!!!!!!!

반응형