티스토리 뷰

iOS

UnitTest의 사용법

Zedd0202 2017. 3. 22. 23:06
반응형

BoostCamp강의에서 Unit Test를 어떻게 사용하는지 

lingostar님 께서 알려주셨어요. 

저는 Xcode에 이런 기능이 있는지도 몰랐답니다 ㅎㅎ..

정말 유용한 기능인 것 같아요 :)


이 Unit Test를 배운지 꽤 됐는데,

지금에서야 쓰게 되네요 ㅠㅠ

그리고 이 글의 카테로리로 iOS에 넣어야할지...swift에 넣어야할지..

저는 iOS에 넣는 게 맞다고 생각되어서 iOS에 넣었습니다!


자, 이 Unit Test가 뭔지 이제 알려드리겠습니다!


먼저 Unit Test뭔지 아시나요? Test?뭔가를 테스트 하는 그런 것 같죠?

Unit Test에 대한 정의를 먼저 알려드리자면,




유닛 테스트(unit test)는 컴퓨터 프로그래밍에서 

소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차다.

 

즉, 모든 함수와 메소드에 대한 

테스트 케이스(Test case)를 작성하는 절차를 말한다. 


이를 통해서 언제라도 코드 변경으로 인해 문제가 발생할 경우, 

단시간 내에 이를 파악하고 바로 잡을 수 있도록 해준다.

 

이상적으로, 각 테스트 케이스는 서로 분리되어야 한다. 

이를 위해 가짜 객체(Mock object)를 생성하는 것도 좋은 방법이다.

 

유닛 테스트는 (일반적인 테스트와 달리) 

개발자(developer) 뿐만 아니라 보다 더 심도있는 테스트를 위해 

테스터(tester)에 의해 수행되기도 한다.




위키백과에서 가져온  Unit Test의 정의입니다!

그냥 한마디로 

"의도된 대로 정확히 작동하는지 검증하는 절차다."

라고 생각하시면 될 것 같아요.


이제 Xcode에서 이 Unit Test를 하는 방법을 

알려드리겠습니다!


먼저 프로젝트를 열어주세요 :)


Single View Application을 눌러주신 뒤,






꼭!!! 밑의 Unit Tests를 포함시켜 주세요!


Team과 Organization Name, Identifier는 자신의 것으로 해주세요:)



자 , 그러면 저희가 만든 프로젝트를 한번 볼까요?






일반 프로젝트와는 다르게 Test폴더가 하나 만들어진거 보이시나요?

UnitTestTests.swift에 들어가보면,



이렇게 되있는 것을 볼 수 있습니다 :)

testExample같은 함수가 있는 것을 보니 이 파일을

예제를 넣어 테스트를 해보는 곳 같죠?

맞습니다 :)


testExample은 알겠는데 

setup? tearDown?이 뭔지 아시겠나요?






setup() : 초기화코드 -> This method is called before 

the invocation of each test method in the class.


tearDown() : 해체코드 -> This method is called after 

the invocation of each test method in the class.






라고 간단히 말할 수 있겠는데요,



setup함수와 tearDown에 있는 주석을 직역하자면,

"이 메소드는(setup/tearDown) 클래스의 각 테스트 메소드의 

호출 전/후에 호출됩니다" 라고 하네요 :)









애플 개발자 문서에서도 이렇게 setUp과 tearDown을 말해주네요


"setUp () 클래스 메소드는 테스트 케이스가 시작될 때 

테스트 케이스의 첫 번째 테스트가 실행되기 전에 정확히 한 번 호출됩니다."




"tearDown () 클래스 메소드는 모든 개별 테스트가 실행 된 후 

테스트 케이스가 끝날 때 정확히 한 번 호출됩니다."




그래서 이 setup과 tearDown이 도대체 무슨일을 하는지 찾아봤더니,


항목이 존재해야하거나 특정 상태가 필요한 테스트가 있으므로 setUp에 이러한 작업 

(객체 인스턴스 만들기, db 초기화, 규칙 작성 등)을 수행합니다.


또한 각 테스트가 시작된 위치에서 멈춰야한다는 것을 알기 때문에 앱 상태를 초기 상태 (예 : 파일 닫기, 연결, 새로 만든 항목 제거, 트랜잭션 콜백 호출 등)로 복원해야 함을 의미합니다. 이 단계는 tearDown에 포함됩니다.



따라서 테스트 자체에는, 

결과를 얻기 위해 테스트 객체에서 수행 할 동작 만 포함되어야하며

setUp 및 tearDown은 테스트 코드를 깨끗하고 유연하게 유지하는 데 

도움이되는 메서드입니다.


한마디로 좋은 함수들이네요 ㅎㅎ..


그럼 이제, 테스트를 한번 해볼까요?


왜 프로젝트 이름이 Leap일까요?

ㅎㅎㅎ

지금 테스트 해볼것은 윤년입니다!

윤년이 영어로 Leap Year죠?XD

(앞으로 할 예제의 출처는 모두 링고스타님입니다.)


LeapTests.swift파일에 




func testVanillaLeapYear() {

            let year = Year(calendarYear: 1996)

            XCTAssertTrue(year.isLeapYear)

        }

        

         func testAnyOldYear() {

            let year = Year(calendarYear: 1997)

            XCTAssertTrue(!year.isLeapYear)

        }

        

        func testCentury() {

            let year = Year(calendarYear: 1900)

            XCTAssertTrue(!year.isLeapYear)

        }

        

        func testExceptionalCentury() {

            let year = Year(calendarYear: 2400)

            XCTAssertTrue(year.isLeapYear)

        }



위 코드를 추가해주세요. 



자, 추가하면 옆에 작은 마름모가 생겼죠?

그리고 오류도......

네, 아직 Year라는 것을 우리가 안만들어줘서 그래요!

만들어야겠죠?






만들기 전에, 우리가 추가한 코드가 도대체 뭔 코드인지 한번 봅시다. 

다 똑같은 코드니 하나만 볼게요. 


let year = Year(calendarYear: 1996)

 XCTAssertTrue(year.isLeapYear)


year라는 변수를 만들어주고, Year는 클래스나 구조체겠네요.

Year형의 year라는변수를 만들어주면서 calendarYear를 1996으로 해줬습니다.

그리고 year에 있는 메소드를 불러오네요? isLeapYear라구요. 

결과적으로 

내가 지금 넘긴 calendarYear 1996년이 윤년이니??????

라고 물어보네요.


그것을 XCTAssertTrue에서 해줍니다.

딱 보니 True냐 False냐 테스트해주는 것 같네요.


그러면 우리는 Year라는 클래스나 구조체가 필요하겠죠?

그리고 calendarYear변수도 필요할 것 같고,

isLeapYear메소드도 필요할 것입니다.



자, 만들러 가볼까요? 

Year.swift파일을 생성하시고, 



import Foundation


struct Year {

    let calendarYear:Int

    var isLeapYear:Bool{ get {


        }

    }

}


위 코드를 추가해주세요. 

위에서 말한 calendarYear변수와 isLeapYear메소드를 만들어줬죠?

XCTAssertTrue는 참인지 거짓인지 판별하는 함수?니까

당연히 isLeapYear도 Bool형 함수여야 합니다.


자, 어떤 코드를 넣어야 

음 니가 지금 준 년도는 윤년이야! 또는 아니야!

라고 말해줄까요?


윤년의 정의를 아시나요?



년도가 4의 배수이면 윤년으로 하되,

 그 년도가 100의 배수이면 윤년이 아닌걸로 하되, 

400의 배수이면 윤년으로 한다.




이게 먼 소리야

라고 하실 수 있습니다.

그냥 간단히 말해서

그 년도가


400으로 나누어 떨어지는 해는 윤년,
100으로 나누어 떨어지지 않고 4로 나누어 떨어지는 해도 윤년.


이죠?

그러니까 지금 받은 수를 어케어케해서 잘 계산하면 된다는 소리입니다.






return calendarYear%4 == 0 && ( calendarYear%100 != 0 || calendarYear%400 == 0)



자, 이렇게 한 줄로 끝나죠?



자, 이제 오류가 사라졌는지 가봅시다. 



ㅇ...?

아직 안사라졌네요?




왜냐하면!!!!

import를 안해주었기 때문입니다. 




Year.swift가 Leap라는 폴더안에 있으므로 Leap를 import해주어야 합니다.


자 그러면!!!



오류가 없는 아름다운 코드가 생기게 됩니다.


자 이제 진정한 Test를 해보러 갑시다.



테스트하려고 Run해버리면 안됩니다.....그냥 위와같은 하얀 화면만 보실거에요 ㅎㅎ..

그럼 테스트는 어떻게 하느냐!!!


아까부터 거슬렸던!!!!!!



⭐️ 이 마름모들로 테스트를 하는 것입니다.⭐️

ㅎㅎㅎ


마름모에 마우스를 갖다 대볼까요? 



마치 자신을 눌러달라는 듯이 말하고 있네요ㅎㅎ


눌러줍시다ㅎㅎㅎㅎ

그러면

Test Succeed라는 창과 함께



테스트가 완료되었다는 표시?가 나옵니다. 

그리고 성공적으로 테스트를 통과한거죠.


나머지 다 해볼까요? 



짠ㅎㅎㅎ

테스트 예제들이 다 통과했네요!!

틀리면 어떻게 될까요? 



이렇게 에러가 나게 됩니다. 

1996년은 윤년인데 

!year.isLeapYear다.

즉, 윤년이 아니라고 했으니 테스트를 통과하지 못하는 거죠.


자. 이렇게 Xcode의 Unit Test라는 좋은 기능 덕분에 

우리는 우리의 앱을 테스트 해볼 수 있답니다.

ㅎㅎㅎ


Unit Test를 해보는 건 아주 좋은 습관이라고 해요.

하지만, 본 코드를 짜는 시간만큼 Test예제를 또 짜야한다는 번거로움과

만약 테스트를 통과한다고 해도, 생각 못했던 케이스들이 발생 할 수 있으므로

Unit Test를 통과했다고 완벽한 앱은 아닙니다.

XD


도움이 되었으면 좋겠어요!

우리 모두 Unit Test를 잘하는 개발자가 됩시다 :)


반응형