test의 성공과 실패는 기대하는 값과 결과값을 비교하는 과정을 통해 이루어진다.
@testable
@testable import UnitTestSample
테스트 케이스에서 테스트 할 모듈을 import할 때 쓰는 어노테이션
애플리케이션 코드의 모듈을 import
할 때 디폴트로 internal로 지정되어, public
이나 open
같은 접근제어를 지정하지 않으면 다른 모듈에서 접근 할 수 가 없다.
@testable
을 붙이면, 유닛 테스트 타겟이 모듈의 internal인 클래스나 함수에 접근 할 수 있다.
@testable 어노테이션을 붙이고 프로덕트 모듈을 한 번 컴파일한 후부터 테스트 모듈에서 프로덕트 모듈을 인식합니다.
UnitTestBundle로 Test Target을 만들어주면 따로 프로덕트 모듈을 import하지 않아도 인식이 가능한 것 같던데...🤨 다른 차이가 있었던 걸까?
테스트가 커버하고 있는 코드의 양을 측정해주는 툴이다.
✅ 확인 할 수 있는 것
Coverage 수치는 테스트가 실행해온 동안 지나온 모든 코드에 대해 측정된다.
현재 파일을 함께 컴파일시키고 싶은 Target의 ☑️에 체크
overhead
어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등
"
오버헤드란 프로그램의 실행흐름에서 나타나는 현상중 하나입니다. 예를 들어 , 프로그램의 실행흐름 도중에 동떨어진 위치의 코드를 실행시켜야 할 때 , 추가적으로 시간,메모리,자원이 사용되는 현상입니다.
특정 작업을 수행할때 메인 작업에 비해 부수적인 작업의 양이 지나치게 많을때
데이터베이스 시스템 측면에서 부담이 된다는 의미에서 오버헤드가 났다고 합니다.
"
출처: https://labs.tistory.com/46 [My Story]
출처: https://gamestory2.tistory.com/15 [베베의 개발일지]
프로그래밍에서 overhead란 특정 작업을 수행할 때
메인 작업 흐름에서 동떨어진(부수적인) 작업의 양이 많을 때를 의미하는 단어인 것 같다.
스위프트에서 큐와 스택을 만들 때 강력한 도구.라고 한다.
CalculatorItemQueue
의 enqueu
를 파라미터 타입마다 각 메서드로 만들어주었는데, 제네릭 함수를 사용하면 하나로 퉁칠 수 잇을 것 같다.
타입 제약을 주면 특정한 클래스를 상속받거나, 특정한 프로토콜을 준수한 타입만이 들어올 수 있게 할 수 있다.
타입 제약을 CalculateItem
프로토콜을 걸어주고, 매개변수는 T
로 지정해주기
내일 수정해보아야겠다
Array List
vs Linked list
Queue를 어떤 자료구조로 구현할지에 대해 고민해보았다.
Queue는 자료가 선형적으로 나열되고, First-In-First-Out 방식으로 추가/삭제가 이루어진다
따라서 Array List
, Linked List
자료구조를 후보로 생각했다.
Queue는 추가는 마지막 요소에서만 일어나고, 삭제는 첫번째 요소에서만 일어난다는 점을 고려했을 때,
시간복잡도를 기준으로 효율성을 비교해보았다.
자료 구조/시간복잡도 | ArrayList | LinkedList |
---|---|---|
마지막 요소에 추가 | O(1) | O(n) (추가를 하기위해 마지막요소를 탐색하는 시간복잡도까지 고려) |
첫번째 요소 삭제 | O(n) | O(1) |
비교해 본 결과, 두 자료구조의 시간복잡도는 추가/삭제를 함께 고려하면 같다는 결론을 내렸다.
Swift에서 기본으로 제공하는 array의 메서드를 사용하고자 Array List를 선택했다.
아래와 같은 이유로 CalculateItemQueue
을 처음엔 struct로 구현했다.
그런데 멤버 변수인queue
가 메서드를 통해 계속해서 수정되고, 따라서 모든 메서드에 mutating
키워드를 추가해주어야 했다.
그래서 queue는 값이 복사되기보단, 참조가 전달되는 것이 적절한 것 같아 class타입으로 수정해주었다. 그리고 mutating
키워드를 전체적으로 사용할 바엔 class를 쓰는 것이 더 좋은 건가? 하는 의문도 생겼다.
class만이 가지는 능력(상속, 타입캐스팅, Objective-C와 호환)을 사용할 일이 없음에도,
프로퍼티가 메서드내에서 계속해서 수정되어야하는 경우,mutating
키워드를 쓰는 것보다 class를 쓰는 것이 적절한 것일까?
아래와 같은 testcode를 실행해보고 싶었는데,CalculateItem
타입이 Equatable
프로토콜을 준수하지 않기 때문에 비교가 불가했다.
func test_queue에_item이3개일때_dequeue호출시_queue의첫번째요소가_삭제된다() {
//expectation
calculatorItemQueue.enqueue(3.0)
calculatorItemQueue.enqueue(Operator.divide)
calculatorItemQueue.enqueue(100000)
calculatorItemQueue.dequeue()
//result
XCTAssertNotEqual(calculatorItemQueue.queue[0], Number(num: 3.0))
}
CalculateItem
에 Equatable
프로토콜을 채택하고, Number
, Operator
에서 구현 하는 방법을 생각해봤는데, 그럼 Number
타입과 Operator
타입간 크로스 비교는 어려워서 포기했다.
더 좋은 방법이 있을까?
TDD방식으로 처음 개발을 진행하다보니, 커밋을 언제 끊어야할지가 아리송했다🙄
TDD의 한 사이클이 기능 단위와 같다고 생각해서
실패하는 testcode작성
- 프로덕션 코드 작성
- refactor
마다 커밋을 했다.