이 글은 https://maily.so/productlab/posts/ca1ddd27 을 읽고 직접 chatgpt를 훈련시켜본 글입니다.

 

 

원본 링크: https://artificialcorner.com/youre-using-chatgpt-wrong-here-s-how-to-be-ahead-of-99-of-chatgpt-users-886a50dabc54

 

You’re Using ChatGPT Wrong! Here’s How to Be Ahead of 99% of ChatGPT Users

Master ChatGPT by learning prompt engineering.

artificialcorner.com

https://maily.so/productlab/posts/ca1ddd27

 

🚀 당신은 ChatGPT를 잘못 사용하고 있습니다

ChatGPT를 제대로 사용하고 계신 분들은 안보셔도 괜찮아요.

maily.so

1. Few Shot Standard Prompts

1. ChatGPT에게 수행시키고자 하는 작업에 대한 설명, 2. 답변에 대한 예시, 3. 답변을 유도하기 위해 명령어로 프롬프트를 구성하는 방법입니다. 해당 방식으로 질문하면 원하는 방식으로 ChatGPT에게 답변을 받을 수 있습니다.

 

 

 

실패했습니다. 나쁜놈...

 

2. Role Prompting

 

ChatGPT에게 역할을 부여하는 방법입니다. 면접을 준비하고 싶다고 가정해 보겠습니다. ChatGPT에게 "채용 관리자 역할"을 지시하고 해당 역할에 대한 세부 정보를 추가하여 프롬프트를 구성하면 모든 직책에 대한 면접을 시뮬레이션할 수 있습니다.

 

역할을 잘 수행해 나가는 것을 보실 수 있습니다.

 

3. Add personality to your prompts and generate knowledge

- 프롬프트에 개성을 더한다는 것은 ChatGPT에게 말투, 형식, 작가의 전문 분야 등을 부여하는 것을 의미합니다. 예를 들어 '10년 이상의 경력을 가진 ㅁㅁ 분야의 전문가 스타일로 ㅁㅁ 주제에 대해 재미있는 예시를 포함하여 글을 작성하세요.'와 같은 예시를 들어보겠습니다.

 

역할을 잘 수행해 나가는 것을 보실 수 있습니다. (질문 자체도 적절하고 좋은 질문들을 하네요...)

 

4. Chain of Thought Prompting

ChatGPT가 질문에 대한 최종 답변을 제시하기 전에 중간 추론 단계를 거치도록 유도하는 방법입니다. 추론 단계를 거치도록 하면 보다 정확한 결과를 얻을 수 있습니다. 아래 이미지에서 ChatGPT가 추론 단계를 거쳤을 때만 올바른 답변을 하는 것을 확인할 수 있습니다.

 

형식은 보다 더 세부적으로 제공하지만 수학은 잘 못하는 것 같습니다.... 

 

결론

 

ChatGPT에게 역할을 부여하거나 말투, 형식, 작가의 전문 분야 등을 부여하는 것은 올바른 사용법인 것 같습니다. 

하지만 수학 질문이나, 질문 형식을 만드는 것은 조금 더 디테일하게 질문하시길 바랍니다. 

잘못하면 저처럼 잘못된 대답을 얻을 수 있으니까요 ㅎㅎ..

 

최근 ChatGPT Plus가 나왔는데 20달러의 돈으로 구독하여 한 번 사용해 보시는 것도 좋을 것 같습니다.

 

감사합니다.

 

 

 

 

이 글은 8 Meta-learning Tips To Grow Your Skills as a Software Engineer 칼럼을 읽고 정리한 글입니다.

8가지 중 6가지의 토픽에 공감하여 6가지의 내용만 요약하였으며, 글 전체를 읽어보실 분들은 아래 링크를 참고하시길 바랍니다.

 

https://betterprogramming.pub/how-to-learn-learn-faster-and-even-faster-792f29586ea

 

8 Meta-learning Tips To Grow Your Skills as a Software Engineer

How to find opportunities and maximize gain

betterprogramming.pub

 


1. Turn Passive Learning Into Fantasy Making

내가 공부하려는 도구/라이브러리/프레임워크의 제작자인척하며 질의응답을 진행해 지식을 확장시키는 방법입니다.

 

Email SPF에 대해 공부한다고 예시를 들어봅시다.

예시

Q: Email 을 발송할 때 내가 보냈음을 서로 알 수 있는 방법이 있을까?

A: 그럴거면 발신 SMTP와 수신 SMTP가 서로 도메인에 대한 정보를 알고 있어야 할 것 같아.

Q: 그럼 어떤 방식으로 서로 도메인에 대한 정보를 알 수 있을까?

A: 음... 통신 표준이 있을거 같은데... 잠시만 어  RFC 4408에 Sender Policy Framework에 대한 설명이 자세히 적혀 있네 한 번 읽어보고 적용해볼까? 보니까 도메인에 SPF 레코드를 추가할 수가 있네! 여기에 SPF 레코드를 작성하면 될 것 같아.

Q: SPF 레코드는 어떻게 작성해야 돼?

A: gmail 가이드를 보니까 SPF 레코드에 대한 설명이 다루어져 있는 것 같아. v=spf1 include:_spf.google.com ~all와 같이 spf 레코드 정보에 대한 설명이 있는데 좀 더 자세히 알아볼까?

Q: 응. 그런데 SPF 정보가 너무 많으면 그것도 문제 아니야? 예를들면 100만개를 등록했다고 치자. 그럼 이거 호출할때마다 읽는거야?

A: 그런걸 방지하기 위해서 SPF 레코드는 최대 10번의 SPF check를 진행한다고 추가 제약사항이 있네. 근데 이건 프로토콜이라 실제로는 체크를 할 수도, 안할수도 있을 것 같아. 우리는 표준을 지키자

 

2. Never Skip the Fundamentals When Touching a New Domain 

https://betterprogramming.pub/how-to-learn-learn-faster-and-even-faster-792f29586ea

 

기본 요소들을 먼저 파악하면 변화하는 모든 것에 쉽게 적응할 수 있습니다. 새로운 것을 배우기 이전에 어떤 것을 기반으로 하는지 파악하고 이를 공부하는 것을 추천드립니다.

 

3. One Tough Real-World Problem Is Worth 1000 Tutorials

하나의 복잡한 실제 문제를 해결하는 과정에서 개발자는 도메인 지식, 디자인 기술, 코딩 실력, 디버깅 기술 등 여러 측면에서 동시에 상당한 향상을 할 수 있습니다.

 

하나의 어려운 문제는 이상하고 복잡하기 때문에 해결하기 위해서는 문제에 대한 관련 지식의 본질을 파악하고 이를 해결해 나가는 과정에서 모든 부분을 성장시킬 수 있습니다.

 

4. Opportunities in Different Environments: Big vs. Small

대기업과 스타트업에서의 개발 방식은 크게 상이합니다. 많은 사람들이 대기업에 가고싶어 하지만 스타트업에서만 경험할 수 있는 요소들이 존재합니다. 보다 균형 잡힌 성장을 위해서는 큰 프로젝트와 작은 프로젝트 둘 다 경험해가며 성장하는 것이 스스로의 단점을 극복하는 좋은 방법이라고 생각합니다.

 

5. Leverage Corner Opportunities to Expand Your Knowledge Scope

https://betterprogramming.pub/how-to-learn-learn-faster-and-even-faster-792f29586ea

실제 업무에서 우리는 대체적으로 유지 보수 업무를 진행합니다. 직장에서 새로운 기술을 시도하고 싶어도 시간적 여유가 없어 진행하지 못하는 경험을 하셨을 것이라 생각합니다. 

 

조금만 부지런해져 새로운 기술을 연습할 코너 기회를 찾아보세요. 업무가 아닌 곳에서 시도해보는 경험을 하는걸 추천드립니다. 대표적인 방법으로는 오픈 소스 시스템에 기여하는 것이 있습니다.

 

6. You Ought to Love What You Do (가장 핵심!)

마지막으로는 당신이 사랑하는 일을 해야 합니다. 

 

 

이 글을 작성하게 된 이유

열정을 가지고 개발자로서 성장하기 위해 많은 노력들을 하고 있지만 떄로는 내가 가는 길이 올바른 방향인지 고민할 때가 있습니다. 이 글을 읽고 아직 내가 가는 길이 올바르구나라는 생각이 되어 다시 다짐하는 의미에서 작성하였습니다.

 

1~5번 내용도 물론 중요하지만, 이 열정을 오랫동안 유지하면서 사랑하는 일을 꾸준히 해야겠다고 다시 한 번 다짐하게 되었습니다. 

 

나머지 내용들은 지금도 공부를 하면서 진행하고 있다고 생각하지만 1,5는 아직 경험해보지 못한 내용들이라 무언가를 공부할 때 좀 더 제작자인척 생각해보는 시간을 가져보고 OSS에도 기여해보도록 노력해보고자 합니다.

 

이 글을 읽는 다른 개발자 분들도 함께 노력해 보다 더 성숙한 개발자가 됐으면 좋겠습니다.

 

감사합니다. 

이 글은 개발자로 거듭나기⋯ 네 가지 기본 소양을 기억하세요 칼럼을 읽고 요약과 생각을 정리한 글입니다.

https://yozm.wishket.com/magazine/detail/1921/

 

개발자로 거듭나기⋯ 네 가지 기본 소양을 기억하세요 | 요즘IT

개발자라면 어떤 기초 지식을 습득해야 할까? 좋은 개발자가 되려면 어떤 사고방식을 갖춰야 할까? 개발자를 꿈꾸는 당신을 위한 조언이 여기 있다. 한글과컴퓨터, 블리자드, 넥슨, 삼성전자, 그

yozm.wishket.com

 

개발자의 기본 소양

개발자는 평생 공부하는 직업입니다. 빠르게 세상이 변하므로 새로운 하드웨어, 새로운 운영 체제, 새로운 프로그래밍 언어를 빠르게 익힐 수 있는 능력을 갖추는 데 집중해야 합니다. 아래 내용은 개발자로서 기본적으로 알아야 할 지식입니다. 

참고: 개발자로 거듭나기

일잘러가 되기 위한 크리티컬 싱킹(비판적 사고)

크리티컬 싱킹(비판적 사고)는 주어진 일의 앞뒤를 생각하는 습관입니다. '왜 이 일을 해야될까?', ' 이 일을 하다가 말면 어떻게 될까?', '어떤 방식으로 일하는게 최선일까?', 문제의 상하좌우까지 고민하는 사고방식을 습관으로 들이면 모든 일을 더 깊이 들여다볼 수 있습니다.

 

참고: 개발자로 거듭나기

소프트웨어를 개발하면서 왜(why), 어떻게(how), 무엇(what)을, 누가(who), 언제(when)까지 출시해야 하는지를 종합적으로 고려해야 합니다. ‘어떻게’에 매몰되면 좁은 영역에서 해결책을 얻을 수는 있지만 종합적인 관점에서 최고 혹은 최선의 해결책을 얻지 못합니다. 크리티컬 싱킹은 종합적인 관점에서 해법을 구하는 습관입니다. 같은 시간을 투자해도 상대적으로 더 큰 성장을 이끌어냅니다.

 

나에 대한 주인 의식을 가지고 기여한다면 자연스럽게 자신이 성장한 것을 확인할 수 있습니다.

 

특정 언어나 도구와 사랑에 빠지지 마라

특정 언어나 도구와 사랑에 빠지면 최적의 언어와 도구를 선택하지 못합니다. 현업에 바쁘더라도 6개월 주기로 새로운 기술과 도구를 확인하고 공부하는 기간을 갖기를 바랍니다. 개발자의 도구는 역할과 프로젝트마다 달라지기 때문에 다양한 언어와 도구를 사용하는 노력을 필요로 합니다.

 

Github에서 발표하는 프로그래밍 언어 순위(흐름)등 다양한 리서치 조사를 참고해 최신 트렌드 언어가 어떤 것들이 있는지 파악하고 앞으로 사용할 만한 기술을 선택해 공부하는 노력을 지속적으로 해야만 합니다.

 

π자형 인재 되기

프론트엔드 개발자라고 해서 프론트엔드만 알면 안 됩니다. 백엔드를 조금이라도 개발할 줄 알아야 합니다. 개발은 협업의 연속입니다. 원활히 협업하려면 알아야 합니다. 프론트엔드 개발자가 백엔드 개발자에게 안 되는 걸 무조건 해달라고 하면 어떻게 될까요?

 

초당 10만까지만 받을 수 있는 시스템인데 ‘나는 당신 사정은 모르겠고 당장 천만 받아줘’라고 하면 안 됩니다. 풀스택 개발자까지는 안 되더라도 프론트엔드, 백엔드, 데이터베이스, 머신러닝, 클라우드, 안드로이드/iOS 전반에 대한 지식이 있어야 합니다.

 

공부는 할 때 빡세게

개발자가 된 이후 처음, 모르는 게 가장 많은 시기에 최대한 많이 깊게 공부하세요. 기본 지식이 선입견이 되고, 나이 먹게 되면 새로운 걸 받아들이는 속도가 느려집니다. 그래서 개발 경력 초기에 공부해야 합니다.

 

 

글을 읽고..

모든 내용에 대해 공감할 수 있었던 것 같습니다. 개발자는 평생 공부하는 직업이기에 공부하는 것이 싫다면 다른 길을 알아봐야 하는 것, 크리티컬 싱킹을 습관화할 것, 언어,도구와 사랑에 빠지지 말 것, 젊을 때 하나라도 더 공부할 것 이 모든게 필요하다고 생각됩니다.

 

이 글을 읽고 처음으로 고민했던 부분은 현재 '특정 언어와 사랑에 빠진 상태'인 것 같다는 생각이 들어 이 부분을 어떻게 개선해 나가야 할까 고민을 하게 된 것 같습니다. 아직 익숙하지 않은 병렬 프로그래밍, 람다, 스트림에 대한 공부를 진행한 이후 조금 더 다른 언어, 도구에 대한 공부를 조금씩이라도 진행해야 될 것 같다는 생각이 듭니다.

 

일잘러가 되기 위해 항상 업무를 하기 이전, 도중에 크리티컬 씽킹을 습관화 하려고 노력해봐야 될 것 같습니다. 평소에는 상황 분석을 짧게해 서너번 재작업을 한 경우가 존재하는데 이런 문제상황을 발생시키지 않기 위해서는 개발 이전에 문제 해결에 대한 타당한 이유를 가지고 문제를 해결하는 습관을 가져야 될 것 같습니다.

 

여러분은 어떤 생각이 들었나요? 

 

읽어주셔서 감사합니다. 

이 글은 Test Doubles을 읽고 내용 정리 및 개인 의견에 대해 작성하였습니다.

Test Double 이란?

단위 테스트는 개발자의 생산성을 유지하고 코드의 결함을 줄이는 데 중요한 도구입니다. 간단한 코드에 대해서는 작성하기 쉬울 수 있지만 코드가 복잡해지면 작성하기가 어려워집니다.

Test Double은 이러한 경우에 유용합니다. Test Double이란 테스트에서 실제 구현을 대신할 수 있는 개체 또는 메소드를 말합니다. Test Double을 통해 실제로 실행하지 않고 무거운 메소드가 호출되도록 하는 등 시스템의 특정 세부 정보를 검증할 수 있습니다.

Test Double을 사용하는 기술

 

모의 프레임워크

소위 잘 알고있는 Mokito나 mock이 Test Double을 더 쉽게 생성할 수 있게 해주는 소프트웨어 라이브러리입니다. 이 라이브러리에서는 바로 아래서 설명드릴 Stubbing과 Interaction testing을 지원합니다.

Faking

  • 실제 구현과 유사하게 작용하지만 제품에는 적합하지 않은 경량화된 API를 의미합니다.
  • 예시
AuthorizationService fakeAuthorizationService = 
    new FakeAuthorizationService(); 
AccessManager accessManager = new AccessManager( fakeAuthorizationService ):

 

Stubbing

  • 자체적으로 동작이 없는 메소드에 동작을 부여하는 프로세스입니다. 메소드에 반환할 값을 정확히 지정하며, 이 반환되는 값을 Stub이라 부릅니다.
  • ex) when(...).thenReturn(...)

 

Interaction testing (mocking)

  • 구현된 메소드를 실제로 호출하지 않고 메소드가 호출되는 방식을 검증하는 방법입니다. 메소드가 올바른 방식으로 호출되지 않을 경우 테스트가 실패합니다.
  • ex) verify(...)

Google에서 본 Test Double

Test Double은 복잡한 시스템에서 귀중한 테스트 도구로서의 수단이 될 수 있습니다. 수많은 개발자들이 mocking framework를 통한 개발을 진행중에 있으며 손쉽게 테스트 코드를 작성할 수 있다는 점에서 많은 사랑을 받고 있습니다.

하지만 mocking framework의 남용은 실제 구현과 동기화되지 않을뿐더러 리팩토링을 어렵게 만드는 반복 코드가 생성되는 문제점을 야기했습니다.

 

단위 테스트가 Test Double에 너무 많이 의존하는 경우, 엔지니어는 통합 테스트를 실행하거나 기능이 예상대로 작동하는지 수동으로 확인해봐야 동일한 수준의 신뢰를 얻을 수 있습니다.

이러한 추가 작업을 수행할 경우 개발자가 실제 구현된 객체를 사용한 테스트 수행 시간에 비해 시간이 너무 많이 소요되는 문제가 발생하며, 수동으로 확인하는 작업을 건너뛸 경우 버그가 발생할 수 있는 딜레마가 발생합니다.

 

Google에서는 이러한 스타일의 테스트가 확장하기 어렵다는 것을 알게되었고 테스트 중인 시스템을 설계할 때 엄격한 지침을 따르도록 정책을 변경했습니다.
테스트에서 실제 구현을 선호하는 것을 클래식 테스트라 부르는데 Google 엔지니어들은 클래식 테스트 스타일에 더 적합한 방식으로 코드를 작성하게 되었습니다.

@DoNotMock annotation

모의 프레임워크에 과도하게 의존하는 테스트를 방지하고자 Google은 다음과 같은 어노테이션을 만들었습니다.

@DoNotMock("Use SimpleQuery.create() instead of mocking.")
public abstract class Query {
  public abstract String getQueryValue();
}

다음 어노테이션을 사용할 경우 "해당 클래스는 무조건 클래식 테스트로 구현해!"라는 의미를 API 소유자가 코드에 의미를 담았다고 생각하시면 좋을 것 같습니다.
그렇다면 Google은 도대체 어느 경우에 Test Double을 사용하는 걸까요?

Test Double을 고려해야 되는 테스트는 무엇일까?

Google은 테스트에서 실제 구현된 객체를 사용하는 방식을 선호한다고 했으나 일부 상황에서는 Test Double 사용을 고려해볼 필요가 존재합니다.


테스트 코드 작성시 클래식 테스트와 Test Double 두 가지 중 하나를 선택한다고 할 때 상호간의 trade-off가 존재하기 때문에 만약 Test Double을 사용할 경우 다음과 같은 사항들을 고려해야 합니다.

Execution time (실행 시간)

단위 테스트의 가장 중요한 특성 중 하나는 빨라야 한다는 것입니다. Test Double은 실제 구현된 코드가 느릴 경우 유용하게 사용할 수 있습니다.

 

ex) 실제 구현된 메소드 테스트시 호출당 1초가 소요된다 했을 때 5개의 tc를 생성할 경우 5초 소요

 

이렇게 실제 구현된 내용을 사용할 경우 빌드 및 테스트 시간에 오랜 시간을 소요해야 된다는 단점이 존재합니다.
'어떤 것이 옳다' 하는 확실한 답이 존재하지 않기 때문에 개발자의 가치관에 따라 클래식 테스트 방식을 선택할지 Test Double을 선택할지가 결정됩니다.

Determinism (결정론)

테스트를 실행하면 항상 동일한 결과가 나오는 경우 테스트는 결정적 입니다 . 반대로 테스트가 시스템이 변경되지 않은 경우에도 결과가 변경될 수 있는 경우가 있는데 이를 비결정적이라 부릅니다. (ex) 외부 시스템 api 호출)

 

테스트는 항상 통과하거나 항상 실패하기에 테스트의 비결정성으로 취약성이 발생할 수 있습니다. 이러한 취약성이 자주 발생하는 경우 Test Double 사용을 고려합니다.

Dependency construction (종속성 구성)

실제 구현을 사용할 때 모든 종속성을 구성해야 하는 문제가 존재합니다. Test Double에는 종속성이 없는 경우가 많으므로 실제 구현된 내용을 이용하는 것보다 Test Double을 이용하는 것이 테스트 코드 작성간 훨씬 간단할 수 있습니다.

Test Double 기술별 사용방법

Faking

실제 구현을 사용하는 것이 테스트 내에서 가능하지 않은 경우 가장 좋은 옵션은 Faking 기법을 대신 사용하는 것입니다. Faking은 실제 구현과 유사하게 동작하여 다른 Test Double 기술보다 선호되는 방식입니다.

예시

// This fake implements the FileSystem interface. This interface is also
// used by the real implementation.
public class FakeFileSystem implements FileSystem {
  // Stores a map of file name to file contents. The files are stored in
  // memory instead of on disk since tests shouldn’t need to do disk I/O.
  private Map<String, String> files = new HashMap<>();
  @Override
  public void writeFile(String fileName, String contents) {
    // Add the file name and contents to the map.
    files.add(fileName, contents);
  }
  @Override
  public String readFile(String fileName) {
    String contents = files.get(fileName);
    // The real implementation will throw this exception if the
    // file isn’t found, so the fake must throw it too.
    if (contents == null) { throw new FileNotFoundException(fileName); }
    return contents;
  }
}

 

Faking의 장점

  • Faking은 빠르게 실행되고 실제 구현을 사용할 때의 단점 없이 코드를 효과적으로 테스트할 수 있도록 도와줍니다.
  • 모든 종류의 API를 Faking으로 정의한다고 가정해보면 소프트웨어 조직 전체의 개발 속도를 향상시킬 수 있습니다.
  • 테스트 속도가 실제 구현 로직보다 빠릅니다.

Faking의 단점

  • 명확하지 않은 Faking은 취약점을 유발하며 올바른 테스트가 되지 않을 수 있습니다.
  • 실제 구현과 유사하게 동작해야 하므로 만드는데 더 많은 노력과 도메인 경험이 필요합니다.
  • 유지관리가 필요하며, 실제 구현이 변경될 경우 Faking 객체 또한 변경되어야 합니다.
  • 내부적으로 Faking 객체에 대한 자체 테스트를 필요로 합니다.

 

Google의 일부 팀은 Faking을 이용한 API를 제공해 다른 팀에서 이용할 수 있도록 제공하여 전체적인 개발 속도를 향상시켰습니다.

이러한 장단점들을 고려하며 Faking 기법을 이용하는 것이 과연 실제 구현된 로직을 이용하는 것보다 생산성 향상을 가져다 줄 것인지 한 번 더 고민해봐야 합니다.

Stubbing

Stubbing은 테스트에 적용하기가 매우 쉽기 때문에 실제 구현을 사용하는 것이 쉽지 않을 때마다 이 기술을 사용하고 싶을 수 있습니다.
그러나 Stubbing을 과도하게 사용하면 이러한 테스트를 유지해야 하는 개발자의 생산성이 크게 저하될 수 있습니다.

Stubbing 남용 예시

@Test public void creditCardIsCharged() {
  // Pass in test doubles that were created by a mocking framework.
  paymentProcessor = new PaymentProcessor(mockCreditCardServer, mockTransactionProcessor);

  // Set up stubbing for these test doubles.
  when(mockCreditCardServer.isServerAvailable()).thenReturn(true);
  when(mockTransactionProcessor.beginTransaction()).thenReturn(transaction);
  when(mockCreditCardServer.initTransaction(transaction)).thenReturn(true);
  when(mockCreditCardServer.pay(transaction, creditCard, 500)).thenReturn(false);
  when(mockTransactionProcessor.endTransaction()).thenReturn(true);

  // Call the system under test.
  paymentProcessor.processPayment(creditCard, Money.dollars(500));

  // There is no way to tell if the pay() method actually carried out the
  // transaction, so the only thing the test can do is verify that the
  // pay() method was called.
  verify(mockCreditCardServer).pay(transaction, creditCard, 500);
}

 

리팩토링한 테스트

과도한 Stubbing을 피하기 위해 mockCreditCardServer가 아닌 faking 객체인 creditCardServer 혹은 실제 구현된 creditCardServer를 사용할 수 있습니다.

@Test public void creditCardIsCharged() {
  paymentProcessor = new PaymentProcessor(creditCardServer, transactionProcessor);

  // Call the system under test.
  paymentProcessor.processPayment(creditCard, Money.dollars(500));

  // Query the credit card server state to see if the payment went through.
  assertThat(creditCardServer.getMostRecentCharge(creditCard)).isEqualTo(500);
}

 

Stubbing 사용은 언제 적절할까?

테스트 목적을 명확히 하기 위해 Stub된 각 메소드는 테스트의 검증 내용과 직접적인 관계가 있어야 합니다. 그렇기에 각 테스트는 일반적으로 적은 Stub을 가져야만 합니다.

많은 메소드를 Stubbing 해야 하는 테스트는 Stubbing이 과도하게 사용되고 있거나 테스트 중인 시스템이 너무 복잡하여 리팩터링해야 한다는 시그널일 수 있습니다.

 

따라서 일반적으로는 Faking을 통한 구현 또는 실제 구현된 객체를 이용하는 테스트가 가장 적합하지만 테스트가 지나치게 복잡해지지 않도록 하기 위해 일부를 Stubbing하는 방식으로 사용할 경우 가장 합리적인 사용이 될 수 있습니다.

Interaction testing (mocking)

Interaction testing (mocking)의 주요 문제는 테스트 중인 시스템이 제대로 작동하는지 알 수 없다는 것입니다. 또한, 테스트 중인 시스템의 구현 세부 정보를 활용한다는 것입니다.

Interaction testing (mocking)은 언제 적절할까요?

  • 실제 구현된 로직이 너무 느리며 Faking을 사용할 수 없는 경우
    • 대안으로 활용(이상적이진 않으나, 시스템이 예상대로 작동한다는 기본 수준의 신뢰를 제공함)
  • 함수 호출 횟수나 순서가 다르면 원하지 않는 동작이 발생할 수 있는 경우
    • 상태 테스트로는 이러한 로직을 검증하기가 어려움

예시(과도하게 지정한 mocking)

@Test 
public void displayGreeting_renderUserName() {
  when(mockUserService.getUserName()).thenReturn("Fake User");
  userGreeter.displayGreeting(); // Call the system under test.

  // The test will fail if any of the arguments to setText() are changed.
  verify(userPrompt).setText("Fake User", "Good morning!", "Version 2.1");

  // The test will fail if setIcon() is not called, even though this
  // behavior is incidental to the test since it is not related to
  // validating the user name.
  verify(userPrompt).setIcon(IMAGE_SUNSHINE);
}

 

예시(잘 지정된 mocking)

@Test 
public void displayGreeting_renderUserName() {
  when(mockUserService.getUserName()).thenReturn("Fake User");

  userGreeter.displayGreeting(); // Call the system under test.

  verify(userPrompter).setText(eq("Fake User"), any(), any());
}
@Test 
public void displayGreeting_timeIsMorning_useMorningSettings() {
  setTimeOfDay(TIME_MORNING);

  userGreeter.displayGreeting(); // Call the system under test.

  verify(userPrompt).setText(any(), eq("Good morning!"), any());
  verify(userPrompt).setIcon(IMAGE_SUNSHINE);
}



결론

test double이 코드를 종합적으로 테스트하고 테스트가 빠르게 실행되도록 보장할 수 있기 때문에 엔지니어링 속도에 매우 중요하다는 것을 알 수 있습니다.

하지만 이를 오용하면 불분명하고 취약하며 덜 효과적인 테스트로 이어질 수 있기 때문에 개발 생산성이 크게 저하될 수 있으며, 테스트를 안하니만 못하다는 문제점을 가지고 있습니다.

따라서 실제 구현된 로직를 사용할 것인지 또는 Test Double 방식을 이용할 것인지에 대한 선택은 팀 또는 개발자가 적합하다고 생각하는 기준을 몇가지 정의하고 사용해야만 합니다.

TL;DR (요약)

  • Test Double 보다는 실제 구현된 로직을 이용한 테스트가 선호되어야 합니다.
  • 테스트에서 실제 구현을 사용할 수 없는 경우 Faking이 이상적인 솔루션입니다.
  • Stubbing을 과도하게 사용할 경우 테스트는 불문명하고 불안정해집니다.
  • Mocking 테스트는 가능하면 피해야 합니다. 테스트 중인 시스템의 구현 세부 정보를 노출하기 때문에 깨지기 쉬운 테스트로 이어집니다.

개인 의견 (다소 주관적)

 

적절한 Faking Stubbing을 통해 높은 테스트 신뢰도를 제공하자

테스트 빌드 및 실행시간 단축은 개발 생산성에 매우 큰 영향을 준다고 생각합니다.

하지만, 실제 구현된 로직들을 가지고 테스트 코드를 작성해야 한다!라는 글의 방향과 Google의 선택이 올바른지에 대해서는 한 번 더 고민해볼 필요가 있다고 생각합니다.


저는 '적절한 Stubbing과 Faking 객체만 잘 이용한다면 실제 구현된 로직을 테스트 코드로 사용하지 않아도 되지 않을까..?' 라는 입장이어서 굳이 클래식 테스트를 지향하지 않아도 된다는 의견을 가지고 있습니다.

Stubbing과 Mocking을 최소화하고 Faking 객체를 만들어 TC들을 리팩토링한다면 실제 구현된 로직을 테스트 코드에 사용하지 않더라도 신뢰도가 높은 TC를 제공할 수 있다고 생각합니다.

Mocking을 줄이자

mock을 최소화하고 각 로직에 Faking 객체를 좀 더 많이 만들어보는 노력을 해야되지 않을까하는 의견을 제안합니다. 이럴 경우 개발 생산 속도는 떨어지지만 개발자 테스트를 최소화 할 수 있지 않을까 하는 생각을 가지고 있습니다.

@DoNotMock annotation을 활용해보자

Faking이 활성화 될 경우, 일부 TC에 대해 @DoNotMock annotation을 활용해 Faking 객체 또는 실제 구현된 객체를 이용하라는 메세지를 공유하면 더 좋은 TC를 만들 수 있습니다.

Stubbing은 검증하는 로직에 한해서만 사용한다.

테스트 코드 작성시 Stubbing은 검증하는 로직에 한해서 사용되는게 좋지 않을까 합니다.

 

 

다음 글에서는 테스트 프레임워크인 junit을 활용한 테스트 코드 작성에 대해 공유하는 시간을 가져보겠습니다.

 

읽어주셔서 감사합니다.


Reference

Test Doubles
Mock Roles, not Objects
State Verification

'기타 > 테스트' 카테고리의 다른 글

4. How to Migrate and Using Junit 5  (0) 2023.05.01
3. Junit 5  (0) 2023.05.01
1. 테스트 코드는 왜 만들까?  (0) 2023.04.08

+ Recent posts