brunch

You can make anything
by writing

C.S.Lewis

by 웅쓰 Jan 26. 2022

Swift는 왜 Mokito가 없나요?

Mocking Framework가 없는 유일한 모던 언어

안녕하세요! iOS 개발하는 웅쓰입니다 :]

새해가 밝은지 어느새 한 달이 다 지나가고 있습니다... 늦었지만 다들 새해 복 많이 받으세요 (__)

얼마 전 저희 파트 iOS 진영에서 테스트 코드와 관련해 토론의 장(?)이 열렸었는데요.

이를 듣고 계시던 노아(안드로이드 개발자)가 iOS는 모키토 같은 게 없냐는 질문을 해주셨었습니다.

모키토는 iOS 외길 인생인 저에겐 매우 생소했고.. 물론 테스트 관련 프레임워크들은 있지만 대다수가 사용한다는 그런    들어봤기 때문에,  iOS 없을까 라는 의문을 갖게 되었습니다.


안드로이드뿐만 아니라 대부분 언어에서 모키토는 거의 사용하는, 사실상 표준 같은 느낌이라던데...

왜 우리만 없을까..... 해서 찾아보다가

관련 글 Swift: The Only Modern Language without Mocking Frameworks 을 찾아서 오늘은 이 글을 공유해드리려고 합니다!





(글이 2020년 9월에 업데이트된 것 같긴 하지만, 2015년도에 발행되었던 글인 점 감안하고 봐주시고 의역과 오역이 있을 수 있으니 정확한 내용은 원문을 참고해주세요 :) 인용구는 따로 해석하지 않고 그대로를 옮겼습니다.)



Swift는 safe language로 설계되었고 기대에 어긋나지 않습니다. 애플은 다음과 같이 설명합니다.

Swift is a new programming language for iOS, OS X, watchOS, and tvOS apps that builds on the best of C and Objective-C, without the constraints of C compatibility. Swift adopts safe programming patterns and adds modern features to make programming easier, more flexible, and more fun. Swift’s clean slate, backed by the mature and much-loved Cocoa and Cocoa Touch frameworks, is an opportunity to reimagine how software development works.


type safety와 extensive complier checks 외에도 언어 설계자들은 안전성을 더하기로 결정했는데, readwrite reflection을 허락하지 않기로 한 것입니다. Adrian Kashivsky 의 표현을 빌리면

Remember that reflection in Swift is currently read-only and there’s no way to modify your program at runtime (with Objective-C-derived classes being an exception as you can stillclass_addMethod() in Swift). Perhaps this limitation will be incrementally lifted in subsequent language releases. However, Swift was designed to be safe – bringing true read-write reflection would break that dogma.


대부분의 경우 이런 안전성은 좋은데요. 다른 요소가 당신의 코드를 수정할 수 없게 함으로써 코드가 항상 예상대로 동작한다고 확신할 수 있습니다. Objective-C는 method swizzling 을 통해 런타임에 변경을 허락하고 특정 메서드의 자동 로깅과 같은 다양한 창의적인 변화에 사용될 수 있습니다.


Reflection in Other Languages

모던 언어들 사이에서 Swift는 readwrite reflection을 허용하지 않는 극소수의 언어 중 하나입니다. Java, C#, Go, Ruby, Python, Javascipt, PHP, Perl, Haskell, Lisp and R과 같은 언어들은 런타임에 변경을 허용합니다. 실제로 GitHub에서 인기 있는 상위 15개 언어(2015년도 기준) 중 readwrite reflection을 지원하지 않는 언어는 C, C++, Swift 뿐이죠.


그럼 C랑 C++은 왜 reflection을 지원하지 않을까요? C++은 추가하기에는 너무 많은 작업이 필요하고 매우 복잡할 것입니다. C도 비슷한 이유로 성숙하고 표준화된 언어를 변경하는 데 많은 시간이 걸립니다.


Swift는 C, C++의 경우와는 다를 텐데 왜 reflection을 지원하지 않을까요? 그 대답은 아마 보안에 관한 것일 겁니다. Reflection은 앱에서 또 다른 공격 백터로 Erwann Wernli-Schärer 은 자신의 생각을 다음과 같이 공유했습니다.

The more reflective power you have the harder it is to ensure things are safe as they should. Reflection defeats notably static typing and can lead to run-time errors.


reflection이 보안 위협이라면 다른 메이저 프레임워크는 어떻게 대처하고 있을까요? C# 최신 버전에서 Microsoft는 .NET 4.5부터 훨씬 더 강력한 규칙을 도입했습니다. - 스위프트처럼 모든 코드는 타입 정보를 읽을 수는 있지만 허가된 신뢰할 수 있는 코드만 런타임에 수정이 가능합니다. 여기에 security-critical 코드는 아예 reflection으로 접근할 수 없어서, 민감한 코드는 검사나 수정으로부터 완전히 잠글 수 있는 길이 열렸습니다.


Swift가 .NET과 유사한 제한들을 두면 readwrite reflection을 지원할 수 있을까요? Swift 팀이 이 기능을 생략한 결정에 대해 설명이 없기 때문에 아직은 알 수 없습니다.


Reflection and Mocking

유닛 테스트를 작성할 때 올바른 행위 검증의 핵심은 isolation입니다. Niraj Bhatt 은 다음과 같이 요약합니다.

Isolation is hard in real world as there are always dependencies (collaborators) across the system. That’s where concept of something generically called ‘Test Double’ comes into picture. A ‘Double’ allow us to break the original dependency, helping isolate the unit (or System Under Test (SUT) – as commonly referred)


- Dummy: 가장 심플합니다. 테스트에 넘겨줄 placeholder

- Fake: 테스트를 쉽게 통과할 수 있도록 의존성을 단순화시키는 데 사용됩니다.

- Stub: 협력 객체나 의존성이 주는 간접적인 인풋을 SUT에 제공하기 위해 사용됩니다.

- Mock: 행위 검증을 사용합니다. 협력 객체와 상호작용 하는 동안 SUT가 올바르게 동작하도록 기대치를 설정할 수 있습니다.

- Spy: 행위 검증의 변형으로 예상되는 행동을 설정하는 대신, 협력 객체에게 온 요청을 기록합니다.


Dummies, fakes, stubs, mocks and spies는 모든 현대 언어에서 단위 테스트의 빌딩 블록들입니다. 이러한 것들은 직접 만들거나 많은 보일러 코드를 제거해 읽기 쉬운 API를 제공하는 mocking framework를 사용해 만들 수 있습니다.


Mocking frameworks는 reflection 위에 만들어지며, 런타임에 객체나 타입, 클래스를 바꿀 수 있다는 장점을 이용합니다. 그들은 기능적으로 존재하는 class를 다른 stub이나 mock 또는 spy 등으로 수정합니다. 그들은 일반적으로 직접 객체들을 조립할 때보다 더 편한 API들을 제공합니다.


The Language with No Mocking Framework

C, C++을 제외하고 모든 인기 있는 언어는 개발자가 사용할 수 있는 mocking frameworks을 가지고 있고 확실히 많이 사용하고 있습니다. 자바 Mockito는 테스트 도구이자 모든 자바 라이브러리 중 상위 10위 안에 드는 라이브러리입니다. Objective-C에서는 OCMock 이 가장 많이 사용되며 C#에서는 Moq와 Javascript는 Sinon 그리고 JSMockito가 인기 있는 것들입니다.


Swift는 readwrite reflection을 지원하지 않기 때문에 mocking 관련 유명 프레임 워크를 만들지 못하고 언어를 떠납니다. mocking, stubbing, spying 은 여전히 잘할 수 있지만, 매 테스트마다 헬퍼 클래스를 직접 만들고, 유사한 보일러 플레이트 코드를 여러 번 만들어야 합니다.


이게 정말 나쁜 걸까요? Uncle Bob을 포함한 많은 단위 테스트 지지자들은 종종 mocking frameworks 가 남용되고 있다고 말합니다. 그래서 밥 아저씨는 mocking frameworks를 사용하지 않는 것에 대해 다음과 같이 조언합니다. - Swift 개발자는 여기에 익숙해져야 할 것입니다.

I don't often use mocking tools. I find that if I restrict my mocking to architectural boundaries, I rarely need them.
Mocking tools are very powerful, and there are times when they can be quite useful. For example, they can override sealed or final interfaces. However, that power is seldom necessary; and comes at a significant cost.
Mocking across architectural boundaries is easy. Writing those mocks is trivial.
Writing your own mocks forces you to give those mocks names, and put them in special directories. You'll find this useful because you are very likely to reuse them from test to test.
Writing your own mocks means you have to design your mocking structure. And that's never a bad idea.


write your own mocks. Swift에서는 밥 아저씨의 조언을 따르는 것 외에 다른 방법이 없습니다. C, C++에서 swift로 이어지는 개발자이 프레임워크를 갖는 걸 포기할까요? 아마 그럴 것입니다. Objc에서 가장 인기 있는 OCMock을 만든 Erik Dörnenburg 보다 이를 더 잘 아는 사람은 없을 겁니다. Swift에서 mocking 프레임워크가 필요한지에 대한 질문에 그는 다음과 같이 말합니다.

Mock frameworks have proven convenient in many languages. It's not that they are essential, but they do add convenience. Stubbing a factory method to return a mock is quick and easy. Creating a protocol and a wrapper, and using dependency injection is probably more sustainable, but it is also more work and looks more complex. As ever, having options and making the right choice seems key.


좋든 싫든 간에 Swift에서 앞으로 나아가는 길은 밥 아저씨의 충고를 따라 자신의 mocks을 사용하는 것입니다. 이것은 증명되고 지속 가능한 접근 방법입니다. - 그래도, 선택권이 있다면 좋았을 것입니다.








읽고 난 소감은,, 역시 애플이 애플 했다!

write your own mocks. iOS를 선택했으니 당연하게 걸어야 할 길이죠! 이래서 iOS가 좋습니다!!

.... ㅎ


reflection이라는 개념도  몰랐는데 이번에 관련  따라 읽으면서 몰랐던 것들도 많이 배운  같네요!

긴 글 읽어주셔서 감사합니다 !



.

.

.



새해에도



우리는 채용 중

https://careers.kakao.com/jobs/P-12253








매거진의 이전글 Rx에서 Swift Concurrency 사용하기
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari