티스토리 뷰

반응형

WWDC 2017 - Engineering For Testability 의 내용이 좋아서 기록해둡니다 

이 발표에서는 이렇게 두가지 세션이 있습니다 

그 중, 첫번째 세션이라고 할 수 있는 Testable App Code에 관한 기록입니다...!! 

 

 

이 세션에서는 'Testable한 코드의 특징이 무엇인지와 그런 코드를 만들기 위한 스킬' 에 대해 알려줍니다.

결론부터 말하자면, 

1) Testable한 Code는 다음과 같은 특징을 가집니다

 

 

2) Testable한 Code를 만들기위해 두가지 스킬을 쓸 수 있습니다 

 

 

이제 본격적으로 Testable한 코드로 리팩토링해봅시다....!! 

그 전에 Unit Test의 구조부터 봅시다 

input을 준비합니다. 테스트되어야하는 코드(보통 함수를 말함)에 input을 넣습니다. 그 결과로 나온 output을 검증하는 방식입니다 

 

이제 진짜 예제를 살펴봅시다 

첫번째, 프로토콜과 파라미터화 기술로 Testable한 코드 만들기

우리가 리팩토링해볼 첫번째 예제는 이 화면에서 open버튼을 눌렀을 때 필요한 일을 해주는 openTapped함수입니다

 

 


하지만 위 처럼 코드를 짜면 테스트할 때 무엇을 assert할지 모르는 상황이 발생합니다 

 

 

프로토콜과 파라미터 기술을 써먹으며 리팩토링 해봅시다...!!! 

 

우선 DocumentOpener라는 클래스를 만들고 openMode를 enum으로 변경해줍니다. 그 다음 open함수가 두 개의 파라미터(Document와 OpenMode)를 받게 변경해줍니다 

 

까맣게 색칠한 부분에서 shared를 쓰는 것이 아직 마음에 걸립니다...!!! 

 

그래서 이렇게 생성자에 application을 주입받게 만들고 기본 값을 shared로 설정해줍시다 

 

 

그에 따라 shared를 써줬던 부분도 application으로 바꿔줍니다 

 

그럼 test에서 app을 이런식으로 쓸 수 있게 됩니다 👍

 


여기까지 파라미터화 하는 기술이였고, 이제 프로토콜 기술을 활용해봅시다 

URLOpening이라는 프로토콜을 만들어줍니다 

 

 

그리고 UIApplication이 URLOpening 프로토콜을 따르게 만들어 줍니다
이미 UIApplication에서 URLOpening 프로토콜이 요구하는 함수 두 개를 구현하고 있기 때문에 따로 구현할 필요없습니다

 

 

그러면 예전에 이렇게 구현했던 것을 

 

 

이렇게 프로토콜 변수(?) 로 바꿀 수 있게 됩니다..!! 

 

 

그에 따라 예전에 이렇게 구현했던 open함수도

 

 

이렇게 바꿔줘야합니다 

 


이제 MockURLOpener를 만들 수 있게 되었습니다 

이렇게 URLOpening을 따르게 해주고 두 함수만 구현해주면 됩니다ㅎㅎ 

 

 

이 세션에서는 이런식으로 만들어주었네요 

 

 

이제 드디어 test에서 assert문을 쓸 수 있게 되었습니다...!!! >___< 

 

 

우리가 한 짓(?)을 돌이켜보면 이렇게 되겠네요  

 

 

우리는 여태까지 Testability 기술의 첫번째를 살펴보았는데, 이제 두 번째를 살펴봅시다 

 

 

두번째, Logic과 Effects를 분리해서 Testable한 코드 만들기

 

이런 클래스가 있고 

 

 

이 클래스는 cleanCache함수를 가지고 있습니다 

 

이 메소드를 어떻게 테스트할 지 생각해봅시다..!! input은 무엇인가요? output은 무엇인가요?! 

우선 input을 생각해보자면, 하나는 maxSize 하나는 currentItems라고 할 수 있습니다  

 

 

여기서 key포인트는 currentItems는 파일매니저가 disk에 있는 파일을 retrieve한 리스트라는 점입니다...!! 이 부분은 테스트 할 때 다뤄야할 dependency 라고 할 수 있습니다 

 


그리고 이 함수는 return value가 없습니다. 그래서 output은 데이터가 될 수 없습니다 

 

 

위의 함수를 리팩토링해줍시다.

1) output을 검증하기 위해 file system에서 지워야할 아이템들을 return하게 바꿔줍시다. 

2) 위의 함수는 file system에 dependency를 가집니다. 그래서 몇몇의 파일이 디스크에서 지워질 부작용이 생길 수 있습니다. 예를 들어 지우는 로직이 잘못되었다면 엉뚱한 아이템을 지울 위험이 있겠죠. 이 부분도 개선해줍시다. 

 

앞에서 살펴봤던 프로토콜 & 파라미터화 기술과 함께 logic과 effect를 분리시켜주는 기술을 써봅시다!! 

CleanupPolicy라는 것을 만들어줄 것입니다 

 

 

이것은 프로토콜이고 이 프로토콜을 따르면 지워야할 아이템들을 리턴해주는 함수를 구현해주어야합니다 

 

 

이 프로토콜을 따르는 MaxSizeCleanupPolicy를 만들어줍니다 

 

 

그러면 검은 색으로 밑줄 친 두 개가 input이 됩니다. maxSize와 현재 디스크에 있는 아이템들을 받으니까요! 

 

 

그리고 itemsToRemove함수가 리턴해주는 아이템들이 output이 됩니다 

 

 

앞서 말했던 리팩토링 방향 2가지를 충족시키게 되었습니다. 

1) 우리의 함수는 functional style이 되었습니다. input, output을 비쥬얼라이즈했습니다. 

 

2) 앞서 말했던 부작용을 없앴습니다. 지우는 로직을 확실히 테스트한 뒤, 지우는 액션을 수행해줄 것이니까요..!!! 

 

 

그래서 이렇게 테스트 코드를 작성할 수 있게 되었습니다

 

 

cleanCache함수를 policy를 주입받게 바꿔줍니다. 앞서 테스트를 거친 MaxSizeCleanupPolicy를 파라미터로 넣어서 사용할 수 있습니다.

 

 

리팩토링하기 전과 비교해볼까요?!? 리팩토링하기전 모습입니다!! 

 

 

리팩토링하기 전, cleanCache함수는 지우는 로직과 지우는 액션을 모두 들고 있었습니다.

하지만 리팩토링 후, CleanupPolicy로 지우는 로직이 빠지고 cleanCache는 지우는 액션만 수행하게 되었습니다. 이것을 Logic과 Effect를 분리했다 라고 말하는 것 같습니다. 너무 괜찮은 것 같습니다 👍👍



여태까지 우리가 한 짓(?) 돌이켜보면 다음과 같습니다 

 

 

 

마무리하자면....!!! Testable한 코드를 만들기 위해 두가지 스킬을 잘 기억하고 써먹어야겠네요 : ) 

 

반응형
댓글