09.11.21 릴리 TIL

🤓 오늘 공부한 내용


1. Unit Test

test의 성공과 실패는 기대하는 값과 결과값을 비교하는 과정을 통해 이루어진다.

참고 글
🐻 야곰닷넷: Code Coverage
소프트웨어 테스팅과 스위프트에서의 Unit Testing

@testable

@testable import UnitTestSample

테스트 케이스에서 테스트 할 모듈을 import할 때 쓰는 어노테이션

애플리케이션 코드의 모듈을 import할 때 디폴트로 internal로 지정되어, public이나 open같은 접근제어를 지정하지 않으면 다른 모듈에서 접근 할 수 가 없다.
@testable을 붙이면, 유닛 테스트 타겟이 모듈의 internal인 클래스나 함수에 접근 할 수 있다.

@testable 어노테이션을 붙이고 프로덕트 모듈을 한 번 컴파일한 후부터 테스트 모듈에서 프로덕트 모듈을 인식합니다.

UnitTestBundle로 Test Target을 만들어주면 따로 프로덕트 모듈을 import하지 않아도 인식이 가능한 것 같던데...🤨 다른 차이가 있었던 걸까?


Code coverage

테스트가 커버하고 있는 코드의 양을 측정해주는 툴이다.

확인 할 수 있는 것

  • 실제 테스트에서 어떤 코드가 실행되었는지
  • 정확성, 성능에 대해 얼마나 충분히 테스트가 이루어졌는지
  • 테스트가 포함하고 있지 않은 코드는 무엇인지

Coverage 수치는 테스트가 실행해온 동안 지나온 모든 코드에 대해 측정된다.


Target membership

현재 파일을 함께 컴파일시키고 싶은 Target의 ☑️에 체크

2. overhead 개념

overhead
어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등

"
오버헤드란 프로그램의 실행흐름에서 나타나는 현상중 하나입니다. 예를 들어 , 프로그램의 실행흐름 도중에 동떨어진 위치의 코드를 실행시켜야 할 때 , 추가적으로 시간,메모리,자원이 사용되는 현상입니다.

특정 작업을 수행할때 메인 작업에 비해 부수적인 작업의 양이 지나치게 많을때
데이터베이스 시스템 측면에서 부담이 된다는 의미에서 오버헤드가 났다고 합니다.
"

출처: https://labs.tistory.com/46 [My Story]
출처: https://gamestory2.tistory.com/15 [베베의 개발일지]


프로그래밍에서 overhead란 특정 작업을 수행할 때
메인 작업 흐름에서 동떨어진(부수적인) 작업의 양이 많을 때를 의미하는 단어인 것 같다.

3. Generic

스위프트에서 큐와 스택을 만들 때 강력한 도구.라고 한다.

CalculatorItemQueueenqueu를 파라미터 타입마다 각 메서드로 만들어주었는데, 제네릭 함수를 사용하면 하나로 퉁칠 수 잇을 것 같다.

타입 제약을 주면 특정한 클래스를 상속받거나, 특정한 프로토콜을 준수한 타입만이 들어올 수 있게 할 수 있다.

타입 제약을 CalculateItem프로토콜을 걸어주고, 매개변수는 T로 지정해주기

내일 수정해보아야겠다


🤔 고민한 점


1. Queue 구현 방법 : Array List vs Linked list

Queue를 어떤 자료구조로 구현할지에 대해 고민해보았다.

Queue는 자료가 선형적으로 나열되고, First-In-First-Out 방식으로 추가/삭제가 이루어진다
따라서 Array List, Linked List 자료구조를 후보로 생각했다.

Queue는 추가는 마지막 요소에서만 일어나고, 삭제는 첫번째 요소에서만 일어난다는 점을 고려했을 때,
시간복잡도를 기준으로 효율성을 비교해보았다.

자료 구조/시간복잡도ArrayListLinkedList
마지막 요소에 추가O(1)O(n)
(추가를 하기위해 마지막요소를 탐색하는 시간복잡도까지 고려)
첫번째 요소 삭제O(n)O(1)

비교해 본 결과, 두 자료구조의 시간복잡도는 추가/삭제를 함께 고려하면 같다는 결론을 내렸다.
Swift에서 기본으로 제공하는 array의 메서드를 사용하고자 Array List를 선택했다.


2. CalculateItemQueue 구현시 타입 선택

아래와 같은 이유로 CalculateItemQueue을 처음엔 struct로 구현했다.

  • struct가 default로 권장
  • 스텝1만 고려했을 땐, 상속, 타입캐스팅이 필요없어 보임

그런데 멤버 변수인queue가 메서드를 통해 계속해서 수정되고, 따라서 모든 메서드에 mutating키워드를 추가해주어야 했다.
그래서 queue는 값이 복사되기보단, 참조가 전달되는 것이 적절한 것 같아 class타입으로 수정해주었다. 그리고 mutating키워드를 전체적으로 사용할 바엔 class를 쓰는 것이 더 좋은 건가? 하는 의문도 생겼다.

class만이 가지는 능력(상속, 타입캐스팅, Objective-C와 호환)을 사용할 일이 없음에도,
프로퍼티가 메서드내에서 계속해서 수정되어야하는 경우, mutating키워드를 쓰는 것보다 class를 쓰는 것이 적절한 것일까?


3. 프로토콜을 타입으로 사용하니, 타입간 비교 불가. equatable프로토콜을 conform할 수 없다?

아래와 같은 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))
    }

CalculateItemEquatable프로토콜을 채택하고, Number, Operator에서 구현 하는 방법을 생각해봤는데, 그럼 Number타입과 Operator타입간 크로스 비교는 어려워서 포기했다.

더 좋은 방법이 있을까?


4. TDD 커밋 단위

TDD방식으로 처음 개발을 진행하다보니, 커밋을 언제 끊어야할지가 아리송했다🙄

TDD의 한 사이클이 기능 단위와 같다고 생각해서
실패하는 testcode작성 - 프로덕션 코드 작성 - refactor 마다 커밋을 했다.


좋은 웹페이지 즐겨찾기