블로그

hhw0850

워밍업 클럽 2기 BE 클린코드&테스트코드 DAY 15 미션

Practical Testing: 실용적인 테스트 가이드 수강 후 작성한 DAY 15 미션입니다. Persistence Layer특징 Persistence Layer는 데이터 엑세스에 집중한 레이어이며 비즈니스 로직이 포함되서는 안된다. 오직 데이터에 접근하는 CRUD 역할만 수행해야 한다.테스트 방법 JPA 레포지토리를 상속 받은 레포지토리를 테스트한다. 데이터베이스에 엑세스하는 로직으로만 테스트해야한다. Business Layer특징 Business Layer는 비즈니스 로직을 구현하는 역할을 한다. Persistence Layer와의 상호작용을 통해 비즈니스 로직을 전개시킨다. 가장 중요한 역할은 트랜잭션을 보장해야 한다. 로직을 전개하다가 문제가 발생하면 롤백되어야 한다. 작업 단위에 대한 원자성 보장 책임을 가진다. 테스트 방법 Business Layer테스트는 Persistence Layer를 통합해서 두개의 레이어를 한번에 테스트한다. Presentation Layer특징 Presentation Layer은 외부 세계의 요청을 가장 먼저 받는 계층이고 파라미터에 대한 최소한의 검증을 수행한다. 비즈니스 로직을 전개시키기 전에 유효성 검증을 하는것을 중점으로 한다.테스트 방법 하위의 Business Layer, Persistence Layer를 Mocking 처리하여 테스트한다. 가짜 객체로 대선해서 정상 동작할 것을 가정하고 테스트한다. MockMvc라는 프레임워크를 사용한다.

미션 DAY 18

1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다.@Mock : 가짜 객체를 만들어준다.@MockBean : spring context가 필요한 통합테스트에서 사용한다.@Spy : 여러기능 중 쓰고싶은 곳만 stubbing하고 다른 기능은 실제 객체가 수행한다.@SypBean : spring context가 필요한 통합테스트에서 사용한다.@InjectMocks : 선언된 가짜 객체를 주입해 주는 기능 2. 아래 3개의 테스트가 있습니다. 내용을 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요? (@BeforeEach에 올라간 내용은 공통 항목으로 합칠 수 있습니다. ex. 1-1과 2-1을 하나로 합쳐서 @BeforeEach에 배치) @BeforeEach void setUp() { 1-1. 사용자 생성에 필요한 내용 준비 1-3. 게시물 생성에 필요한 내용 준비 1-5. 댓글 생성에 필요한 내용 준비 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-2. 사용자 생성 1-4. 게시물 생성 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-2. 사용자 생성 2-4. 게시물 생성 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { //given 3-2. 사용자1 생성 3-6. 사용자2 생성 3-6. 사용자1 게시물 생성 3-8. 사용자1의 댓글 생성 //when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }

정재원

인프런 워밍업 클럽 스터디 2기 BE 클린코드 & 테스트 과정- 4주차 발자국

4주차 발자국 회고Presentation Layer 테스트MockMvc 파라미터에 대한 최소한의 검증을 수행한다는 것은 중요하게 생각해 왔지만 해당 부분에 대한 모든 코드는 DTO 객체에서 처리해야만 한다는 생각을 가지고 있었다. 하지만 Validation을 사용해 DTO 객체에서 모든 부분을 확인하는 것은 도메인에 대한 이해를 바탕으로 다른 부분에서 확인해야 할 수도 있다는 코치님의 가르침은 신선하고 흥미로운 부분이었다. 무조건적인 확인이 아닌 좀 더 도메인을 이해하고 그 이해를 바탕으로 검증 시도를 할 수 있는 코드를 작성할 수 있도록 노력해야 함을 느낄 수 있었다.더 나은 테스트를 작성하기 위한 구체적 조언한 문단에 한 주제! 분기에서 나누어지는 모든 상황을 파악하는 것은 하나의 주제라고 생각했지만 그렇지 않았다. 테스트의 제목을 명시하니 그에 대한 이해가 더 크게 다가왔다. 하나의 목적을 두고 그 목적을 저해하지 않는 코드만이 명확한 테스트라는 것은 테스트에 대해 많은 생각을 할 수 있게 된 것 같다.Test Fixture 구성 다양한 테스트를 구성하는데 있어 테스트의 편의성을 추구하고 복잡성을 덜어내기 위해 데이터를 미리 셋업하는 것을 긍정적으로 생각하고 있었지만 자원을 생성할 때 사용되는 파라미터를 중요하게 생각해야 한다는 것은 당연한 말일 수도 있지만 꽤나 충격적이었다. 테스트에 필요한 일련의 객체를 만드는 과정에서 사용되지 않는 즉, 중요하지 않는 파라미터에 대해서는 메서드의 파라미터에서 제외함으로써 현재 진행되는 테스트에서 중요한 것은 무엇인지 읽는 이로 하여금 알려 줄 수 있음을 배운 것은 테스트가 하나의 문서임을 분명하게 깨닫게 해준 것 같다.

백엔드

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 발자국 4주차

강의 : Practical Testing: 실용적인 테스트 가이드@Mock객체가 기대하는 행위와 리턴 값을 지정하여 테스트에서 기대하는 동작만 테스트가 가능하다주로 외부 네트워크를 사용하는 객체에 사용하면 좋다 @MockBean스프링 컨테이너에서 사용하기 위한 @Mock 객체@Spy일부는 Mock 객체처럼 동작만 그 이외에는 실제 객체처럼 동작한다내가 지정한 동작을 기대하는 행위, 반환에 대한 mocking 할 수 있다실제로 많이 쓰이지는 않는다@SpyBean스프링 컨테이너에서 사용하기 위한 @Spy 객체@InjectMocksMock, MockBean 객체를 주입 받는 대상 객체에 사용된다ex) OrderService에 UserService, ProductService 주입이 필요한 경우 BDDMockitogiven, when, then 3단계로 테스트 작성이 가능하다Classicist vs Mockist클래스를 직접 사용하여 테스트할지? Classicist 관심사 외엔 다 목킹하여 테스트할지? Mockist정답은 없지만 개인적인 내 생각으로는 객체간의 협력에 따른 결과가어떤 결과가 나올지 예상 불가하기에 최대한 실제 객체를 사용하는 Classicist가 좀 더 좋아보인다뭐가 정답이라기 보다는 관심사에는 Classicist, 관심사가 아닌 부분엔 Mockist을 적절하게 배치하는게 좋아보인다한 문단에 한 주제테스트 또한 문서의 성격을 띄기 때문에 하나의 테스트에 한 가지 기능만 테스트해야 가독성 좋다테스트 환경/테스트간의 독립성 을 보장하자어떤 환경이던, 어떤 순서로 실행하던 반복가능하며, 테스트가 성공으로 떠야 한다테스트 환경 통합테스트 환경을 빠르게 하기 위해서는 ApplicationContext가 띄우는 횟수를 줄여야 한다layer별로 상위 클래스를 만들고 그 상위 클래스를 상속하는 방식으로 ApplicationContext를 재사용하자private 메서드의 테스트?public 함수 호출 시 내부 private 메소드도 호출되기에 따로 작성 필요없다private 메서드의 테스트가 강력하게 필요하다 느끼면 그건 클래스 분리의 신호!! 

백엔드워밍업클럽2기BE클린코드&테스트

Groot

<워밍업 클럽 2기 - 백엔드 클린 코드, 테스트 코드> 4주차 발자국

강의 수강수강한 강의: Practical Testing: 실용적인 테스트 가이드학습 내용 요약Mocking에 관해 배웠다. 여러 stub과 mocking 기법에 관해서 배우며 정리하는 시간을 가졌다.노트 중 일부말고도 private method에 관한 테스트나 Classicist VS. Mockist 부분에서는 어떤 것이 어떤 상황에 어울리는지 등을 배웠다. 회고이번에 Mock과 Stub애 관해 개념을 제대로 잡으면서 잘못하고 있었던 부분들을 점검할 수 있었다.이번 주를 마지막으로 강의를 모두 완강하게 되었는데 테스트 부분은 수강하며 여러모로 반상하게 되는 시간이기도 했다. 왜 테스트를 하는지, 어떤 관점에서 바라보는지가 매우 중요했고 직접 짜는 것을 보며 배우니 추상적인 부분도 코드로 풀어내는 것을 볼 수 있어서 실전 감각을 익히기 좋았다.미션해결 과정Mock, Stub에 관한 어노테이션들을 정리하고 수도코드로 된 테스트 케이스를 직접 어떻게 짤 것인지 제시해보는 미션을 받았다.모든 테스트 케이스 모두 사용자 하나와 게시글이 필요해서 이러한 공통된 부분은 @BeforeAll에 배치했다. 나머지는 늘하던대로 Given, When, Then 형식으로 작성했다. 실제 코드 작성은 없어서 금방 끝났었다.회고Spy를 사용해본적이 아직 없는데 Spy를 사용해서 테스트 코드를 더 짜봐야겠다는 생각이 들었다. 실제 사용 사례를 좀 더 찾아봐야겠다!그리고 뭔가 마지막 미션이 너무 무난해서 제대로 한건지 궁금하다. 다른 사람의 수행한 결과물도 보며 복습해봐야겠다.

백엔드클린코드자바워밍업클럽2기워밍업2기

zooxop

인프런 워밍업 스터디 클럽 2기 백엔드(클린코드&테스트코드) 발자국 - 4주차

인프런 워밍업 클럽 2기, 백엔드(클린코드&테스트코드) 과정에 참여하고 있습니다.마지막 주차인 이번 4주차에는 Layered Architecture 의 각 레이어별 역할과 실무에 가까운 테스트 방법들을 배워보는 시간을 가졌습니다.강의 링크: Readable Code: 읽기 좋은 코드를 작성하는 사고법 [학습 요약] Layered ArchitecturePersistence LayerData Access의 역할을 한다.~~Repository비즈니스 가공 로직이 포함되어서는 안된다.Data에 대한 CRUD에만 집중한 레이어Business Layer비즈니스 로직을 구현하는 역할Persistence Layer와의 상호작용(Data를 읽고 쓰는 행위)을 통해 비즈니스 로직을 전개시킨다.트랜잭션을 보장해야 한다.작업단위에 대한 원자성Presentation Layer외부 세계의 요청을 가장 먼저 받는 계층파라미터에 대한 최소한의 검증을 수행한다.MockMvcMock: 가짜, 대역의 의미를 갖고 있다.Mock(가짜) 객체를 사용해 스프링 MVC 동작을 재현할 수 있는 프레임워크 Test Double테스트를 수행하기 위한 대역 역할을 하는 객체들을 칭하는 표현Dummy아무것도 하지 않는 깡통 객체Fake단순한 형태로 동일한 기능은 수행하나, 프로덕션에서 쓰기에는 부족한 객체 (ex. FakeRepository)Stub테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체.그 외에는 응답하지 않는다.SpyStub 이면서 호출된 내용을 기록하여 보여줄 수 있는 객체.일부는 실제 객체처럼 동작시키고 일부만 Stubbing 할 수 있다.Mock행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체.Stub과 Mock의 차이Stub은 상태 검증(State Verififation) 을 위해 사용Mock은 행위 검증(Behavior Vefirification) 을 위해 사용 순수 Mockito로 검증해보기@ExtendWith(MockitoExtension.class) class MailServiceTest { @Spy private MailSendClient mailSendClient; @Mock private MailSendHistoryRepository mailSendHistoryRepository; @InjectMocks private MailService mailService; @DisplayName("메일 전송 테스트") @Test void sendMail() { // given // 1) doReturn(true) .when(mailSendClient) .sendEmail(anyString(), anyString(), anyString(), anyString()); // 2) doNothing() .when(mailSendClient) .a(); // when boolean result = mailService.sendMail("", "", "", ""); // then assertThat(result).isTrue(); verify(mailSendHistoryRepository, times(1)).save(any(MailSendHistory.class)); // 3) } } @Spy 객체는 Mockito 의 메서드가 아니라 Stubber 메서드를 이용해서 Stubbing 을 수행해야 한다.1) MailSendClient 의 .sendEmail() 메서드만 Stubbing 했고, 나머지는 실제 구현 코드를 사용한다.2) 이렇게 하면 .a() 도 Stubbing 했으므로, 동작을 안하게 됨.3) verify() 를 이용해서 Mock 객체의 여러가지 행위를 검증할 수 있다. BDDMockitoMockito 를 한번 더 감싸서, 동일한 기능을 제공하되 BDD 스타일로 작성된 메서드를 사용할 수 있도록 도와주는 라이브러리이다.// Before // given Mockito.when(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())) .thenReturn(true); // After // given BDDMockito.given(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())) .willReturn(true);Mockito를 사용하게 되면, given 절에 when() 이라는 이름의 메서드를 사용해야 된다. 이는 부자연스럽게 느껴질 수 있으므로, BDDMockito 를 사용하면 동일하게 when() 동작을 수행하지만 이름은 given() 인 메서드를 사용할 수 있다.  더 나은 테스트를 작성하기 위한 구체적 조언 한 문단에 한 주제테스트 코드는 문서의 역할을 한다. 그러니, 글쓰기를 한다는 마음 가짐으로 테스트를 작성하자. 완벽하게 제어하기현재시간, 랜덤값 등을 외부에서 주입받도록 DI 구조로 리팩토링 하여, given 데이터를 완벽하게 제어할 수 있도록 한다.이메일 발송과 같은 외부 세계와 소통하는 기능은 Mocking 을 통해 제어할 수 있도록 한다. 테스트 환경의 독립성을 보장하자한 테스트 메서드에서 두가지 이상의 기능을 테스트하지 말자논리적인 사고가 한번 더 필요해지므로, 가독성에 안좋은 영향을 준다.when/then 절의 assert 구문을 호출하기 전에 given 에서 예외가 발생할 수도 있다.given절에 사용할 데이터를 만들때는 가급적이면 순수한 생성자 또는 Builder 를 통해 생성하는 것이 좋다.생성 과정에 검증이 포함되어 있는 Factory 메서드 패턴을 사용하면, 생성 과정에서 예외가 발생할 수도 있음. 테스트 간 독립성을 보장하자테스트간에는 순서라는 개념이 없어야 한다.각각 독립적으로, 언제 어떤 순서로 어떻게 수행되든 항상 같은 결과를 내야만 한다. 한 눈에 들어오는 Test Fixture 구성하기Fixture: 고정물, 고정되어 있는 물체테스트를 위해 원하는 상태로 고정시킨 일련의 객체Fixture를 생성하는 코드를 메서드로 분리시킨 다면,이 테스트에서 필요한 파라메터만 넘길 수 있도록 메서드 내부에서 기본값을 하드코딩으로 설정해주는 방법이 가독성 향상에 좋다.@BeforeEach, @BeforeAll중복 코드를 줄이기 위해 사용하는 기능이지만, 각 테스트간 결합이 생기게 만든다는 맹점이 존재함.각 테스트 입장에서 봤을 때, 아래 두가지 항목을 만족하면 BeforeEach 절에 사용해도 괜찮다.아예 몰라도 테스트 내용을 이해하는 데에 문제가 없는가?수정해도 모든 테스트에 영향을 주지 않는가?data.sql테스트 클래스 코드가 아닌, 쿼리로 데이터를 미리 셋업하도록 처리하는 방식은 데이터를 셋업하는 코드의 파편화로 인해, 유지보수 포인트가 증가하고 추후 중복코드를 만들어낼 수도 있는 등 프로젝트의 복잡도만 높이는 행위이므로 지양하는 것이 좋다. Test Fixture 클렌징.deleteAll() vs .deleteAllInBatch()`.deleteAll()` : 지울 테이블을 먼저 select 하고, 데이터 건수만큼 delete 쿼리의 where 절에 key값을 포함한 쿼리가 요청됨.`.deleteAllInBatch()` : 냅다 delete All 쿼리를 요청해버림.그럼 .deleteAll()은 왜 사용??.deleteAll() 은 모든 연관관계를 먼저 찾은 다음 삭제를 해주기 때문에, 외래키 같은 제약 조건을 고려해서 삭제해준다.어지간하면 .deleteAllInBatch()를 사용하자. [후기] 이로써 총 4주간의 워밍업 클럽 일정이 마무리 되었습니다. 지금까지는 인프런 강의를 구매만 해놓고 수강을 미뤄놓기만 해왔는데, 우연한 기회에 알게된 워밍업 클럽 덕분에 밀도있게 학습을 할 수 있는 경험을 겪어본 것이 가장 좋았던 점이었습니다.실무에서도 테스트를 적극적으로 작성하지 않는 상황이 정말 많아, 테스트를 어떻게 하면 더 잘 작성할 수 있는지에 대한 의문점이 항상 있었습니다. 그런 저에게 실용적인 테스트를 작성할 수 있게 실무에 가까운 예제를 알려준 이번 강의가 정말 많은 도움이 되었습니다.좋은 강의를 준비해주신 박우빈 강사님께 감사드리고, 워밍업 클럽이라는 시스템을 마련하고 운영해주신 인프런 운영진분께도 감사드립니다.

백엔드백엔드워밍업클럽테스트코드클린코드

[워밍업 클럽 2기] Day 18 - 모킹 애노테이션의 종류, 테스트 내용 배치

워밍업 클럽 2기: Clean Code & Test Code의 Day 18 미션입니다. 🎯 미션 11. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다. @MockMockito의 기본 모킹 애너테이션Mock 객체를 만들어 해당 객체의 메서드 호출에 대해 미리 정의된 값을 반환하도록 설정 가능(stub)Mock 객체는 실제 메서드를 호출하지 않고 동작만 시뮬레이션 한다@MockBeanMock 객체를 빈으로 등록합니다. 이는 테스트 대상 클래스가 의존성 주입을 통해 해당 Mock 빈을 받을 수 있도록한다.보통 @SpringBootTest나 @WebMvcTest와 같은 Spring 컨텍스트와 함께 사용되는 경우에 적합하다 @SpyMockito에서 객체의 일부 메서드만 모킹하고 나머지는 실제 메서드를 호출할 수 있다객체의 일부 기능만 변경하여 테스트하고 싶은 경우 사용한다실제 객체가 만들어져서 사용된다doReturn().when.() 사용SpyBean부분 모킹을 위해 스프링 컨텍스트에 등록된 실제 빈을 Spy로 대체한다실제 빈의 일부 메서드만 모킹하고, 나머지는 실제 메서드를 호출하게 할 때 유용하다@InjectMocks테스트 클래스에 정의된 @Mock 또는 @Spy로 선언된 객체를 주입하여, 대상 클래스의 의존성을 자동으로 설정한다  🎯 미션 22. 아래 3개의 테스트가 있습니다. 내용을 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요? (@BeforeEach에 올라간 내용은 공통 항목으로 합칠 수 있습니다. ex. 1-1과 2-1을 하나로 합쳐서 @BeforeEach에 배치) As-Is@BeforeEach void setUp() { ❓ } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 1-6. 댓글 생성 // given ❓ // when // then - 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 2-7. 댓글 수정 // given ❓ // when ❓ // then - 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 3-9. 사용자2가 사용자1의 댓글 수정 시도 // given ❓ // when ❓ // then - 검증 } 다음은 미션을 수행한 To-Be 입니다.To-Be@BeforeEach void setUp() { 1-1. 사용자 생성에 필요한 내용 준비, 2-1. 사용자 생성에 필요한 내용 준비, 3-1. 사용자1 생성에 필요한 내용 준비 3-3. 사용자2 생성에 필요한 내용 준비 1-3. 게시물 생성에 필요한 내용 준비, 2-3. 게시물 생성에 필요한 내용 준비, 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-2. 사용자 생성 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then - 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { // given 2-2. 사용자 생성 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then - 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-2. 사용자1 생성 3-4. 사용자2 생성 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then - 검증 }고려한 내용@BeforeEach()에는 각 테스트에서 반복되지만, 검증하는 대상과는 직접적인 관련이 없는 공통 준비 사항을 처리하려고 했다. 여기서 준비하는 내용은 없어도 각 테스트를 이해할 수 있어야 하고, 각 내용이 변경되어도 각 테스트는 정상적으로 수행될 수 있어야 한다.when에는 각 테스트에서 검증하는 행위만을 배치시켰다  🔍 참고Practical Testing: 실용적인 테스트 가이드

백엔드워밍업클럽2기테스트코드Day18모킹

김민성

[워밍업 클럽 스터디 2기 - BE] (클린코드, 테스트코드) day 18 미션

출처 : 인프런 워밍업 클럽 스터디 2기 - 백엔드 클린코드, 테스트 코드(Java, Spring Boot)Practical Testing: 실용적인 테스트 가이드 1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 이 애노테이션들을 한번 정리하고 차이점을 알아보자. @Mockorg.mockito.Mock 이며 Mockito.mock() 을 애노테이션화 한 것으로 볼 수 있다.사용하려면 junit5기준으로 @ExtendWith(MockitoExtension.class)을 클래스 위에 달아주어야 한다.역할은 내가 어떤 테스트를 하고 싶은데, 그 테스트를 하려면 또 다른 의존성(클래스)를 끌고 와야 하는 상황에서 이 의존성을 가짜로 바꿔치기 (Stub)해 주는 것이다.그래서 내가 테스트 하고 싶은 코드만 테스트 할 수 있게 되는 것이다. @MockBeanorg.springframework.boot.test.mock.mockito.MockBean 패키지이며(!) spring-boot-test가 제공하는 애노테이션 이다.이걸 사용하면 스프링 컨텍스트가 관리하는 빈을 대체할 수 있다. → 즉 @SpringBootTest를 사용해야함.mock객체를 스프링 컨텍스트에 대신 등록하는 것이다. 그래서 Autowired에 의존성이 주입됨.역할은 @Mock과 유사하다. @InjectMocksorg.mockito.InjectMocks이며 @Mock이나 @Spy가 붙은 의존성 객체를 내가 테스트 할 객체에 주입할 때 사용하는 애노테이션이다. @Mock private MailSendClient mailSendClient; // 의존성(가짜 객체) @InjectMocks private MailService mailService; //실제 테스트할 객체코드에서 보면 mailSendClient라는 가짜 객체를 테스트를 위해 mailService에 주입하겠다는 것이다. @Spyorg.mockito.Spy이며 Mockito.spy()를 애노테이션화 한 것으로 볼 수 있다.의존성을 대체하는 @Mock과 같은 역할을 하지만 한 가지 큰 차이점이 있다.@Spy를 사용하면 일부 기능은 가짜로 Stub할 수 있고, 일부 기능은 실제로 동작 시킬 수 있다. @Slf4j @Component public class MailSendClient { // 메일 전송 public boolean sendEmail(String fromEmail, String toEmail, String subject, String content) { log.info("메일 전송"); throw new IllegalArgumentException("메일 전송"); } public void a() { log.info("a"); } public void b() { log.info("b"); } public void c() { log.info("c"); } }다음과 같은 가짜로 대체하고 싶은 클래스가 있다. 여기서 sendEmail()만 가짜로 Stub하고 나머지 a(), b(), c()는 실제 메서드를 실행하고 싶은 거다.public class MailService { private final MailSendClient mailSendClient; public boolean sendMail(String fromEmail, String toEmail, String subject, String content) { boolean result = mailSendClient.sendEmail(fromEmail, toEmail, subject, content); if (result) { // 추가 로직 } mailSendClient.a(); mailSendClient.b(); mailSendClient.c(); ... } }이런 식으로 MailService에서 sendMail()을 테스트를 할 때 mailSendClient의 sendMail()만 가짜로 쓴다는 의미이다. @Spy private MailSendClient mailSendClient; @InjectMocks private MailService mailService; @Test @DisplayName("메일 전송 테스트") void sendMail() { doReturn(true) .when(mailSendClient) .sendEmail(anyString(), anyString(), anyString(), anyString()); boolean result = mailService.sendMail("", "", "", ""); }이렇게 doReturn().when().스터빙할메서드()이라는 메서드 체이닝을 통해 스터빙할 수 있다. @Spy를 사용하면 일부 기능은 가짜로 Stub할 수 있고, 일부 기능은 실제로 동작 시킬 수 있다. @SpyBean이것도 @MockBean과 마찬가지로 org.springframework.boot.test.mock.mockito.SpyBean spring-boot-test가 제공하는 애노테이션 이다. 즉 @SpringBootTest를 사용해야함.가짜 객체의 일부만 stub하고, 나머지는 실제 메서드를 사용하고 싶을 때 사용.2. 다음과 같은 테스트가 있을 때 이걸 분류해보자.@BeforeEach void setUp() { ❓ } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 1-6. 댓글 생성 // given ❓ // when ❓ // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 2-7. 댓글 수정 // given ❓ // when ❓ // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 3-9. 사용자2가 사용자1의 댓글 수정 시도 // given ❓ // when ❓ // then 검증 }여기서 @DisplayName으로 뭘 테스트할지 알 수 있다.이번 테스트는 댓글에 대한 테스트를 하려는 것으로 느낄 수 있다.그럼 given절에는 댓글을 달기 위한 사전 준비를 해야 하는데, 반복적으로 준비해야 하는 것은 setUp()으로 빼보자.1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성이 내용은 계속 반복된다.@BeforeEach void setUp() { 사용자 생성에 필요한 내용 준비 사용자 생성 게시물 생성에 필요한 내용 준비 게시물 생성 } 이렇게 준비해보자. 첫 번째 테스트는 댓글을 작성할 수 있다가 핵심이기 때문에 다음과 같이 나타냈다.@DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 }  두 번째 테스트는 댓글을 수정이 핵심이기 때문에 댓글 생성까지는 준비하고, 핵심인 댓글 수정을 when에서 실행했다.@DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 }  마지막 테스트는 타인이 댓글을 수정 시도한다.이기 때문에given절에선 타인 사용자 2를 만들어주고, 내가 댓글을 생성해 놓는다.그리고 when절에서 타인이 내 댓글을 수정 시도한다.@DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 } 전체 코드는 다음과 같다.@BeforeEach void setUp() { 사용자 생성에 필요한 내용 준비 사용자 생성 게시물 생성에 필요한 내용 준비 게시물 생성 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }  

백엔드테스트코드워밍업클럽미션

[워밍업 클럽 2기 BE 클린코드 & 테스트] 4주차 발자국

 Practical Testing: 실용적인 테스트 가이드 수강과 미션을 진행하고 남긴 4주차 발자국입니다. 강의테스트 코드 작성 방법 뿐만 아니라, 테스트에 대한 마음가짐과 관점까지 배울 수 있었습니다. 강의에서 다루는 도구들 외에도 다양한 도구들을 소개해주었고, Hexagonal Architecture와 같이 추가로 학습하면 좋을 내용도 제시해주어 시야를 넓힐 수 있었습니다. 특히 Classicist, Mockist와 같이 테스트를 바라보는 다양한 관점을 접하면서 테스트에 대해 더 깊이 있게 생각해볼 수 있었습니다.'테스트는 문서다'라는 개념이 처음에는 막연하게 느껴졌습니다. 하지만 @DisplayName을 활용한 테스트 설명과 REST Docs를 통한 API 문서화를 실습하면서, 테스트 코드가 어떻게 문서의 역할을 할 수 있는지 구체적으로 이해할 수 있었습니다.Fixture 관리에 대한 부분은 특히 인상적이었습니다. 과거에는 단순히 코드 중복을 줄이는 데만 초점을 맞추었는데, 이번 강의를 통해 테스트 간의 독립성 보장과 가독성 측면에서 Fixture를 다루는 새로운 관점을 배울 수 있었습니다. 미션 (Day15, Day18)강의 내용을 정리하자라는 목표로 미션을 진행했습니다.시간이 부족해서 예시코드나 이전 프로젝트 경험을 녹여 구체적인 표현으로 정리하지 못한 것이 아쉽습니다. 회고워밍업 클럽에 참여하지 않았다면, 두 강의를 끝까지 듣지 못했을 것 같습니다. 4주간의 진도표 덕분에 학습 계획을 세우는 부담이 줄었고, 이러한 가이드라인이 없었다면 아마도 강의를 끝까지 완주하기 어려웠을 것 같습니다. 다만 중반에 다른 일정과 겹치게 되어 강의는 수강했지만, 충분히 소화하지 못한 부분이 있어 아쉽습니다. 짧은 기간에 많은 것을 채우다보니, 아직까진 작은 기능을 구현해도 배운 내용을 적절히 활용하기 보다는 고려할 것이 너무 많아 머리가 어지러운 경우가 많습니다. 그래도 이 과정이 강의에서 배운 내용을 소화하는 과정이라고 생각합니다. 이 과정이 끝나고 강의를 다시 들으면 이번에는 느껴보지 못했던 새로운 부분이 보일 것 같습니다.

gusdnchl7144

인프런 워밍업 클럽 스터디 2기 - 백엔드 클린코드, 테스트코드 4주차 발자국

 Section7) Mock을 마주하는 자세Test Double의 종류1) Dummy : 아무것도 하지 않는 깡통 객체2) Fake : 단순한 형태로 동일한 기능은 수행하나, 프로덕션에서 쓰기에는 부족한 객체 (ex, FakeRepository)3) Stub : 테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체, 그 외에는 응답하지 않는다. //상태 검증 (State Verification)4) Spy : Stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체, 일부는 실제 객체처럼 동작시키고 일부만 Stubbing할 수 있다,5) Mock : 행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체 //행위 검증 (Behavior Verification).BDDMockitoBDDMockito는 Mockito에서 BDD 스타일에 맞추어 모든것의 이름만 바꾼 것이다.일례로 given 구역에 .when()을 쓰면 이질감이 들기 떄문에 BDDMockito가 생긴 것이다..Classicist VS Mockist1) Classicist- 꼭 필요한 경우에만 mocking을 쓰고 왠만하면 진짜 객체로 테스트 하자는 주의이다.2) Mockist- 모든 것을 Mocking 위주로 하여 테스트 하자는 주의이다..Section8) 더 나은 테스트를 작성하기 위한 구체적 조언1) 한 문단에 한 주제!- DisplayName을 한 문장으로 구성할 수 있어야 한다~!2) 완벽하게 제어하기3) 테스트 환경의 독립성을 보장하자- 테스트에서는 팩토리 메서드를 지양하고 Buider나 생성자를 통해 최대한 독립성을 보장해서 given절을 구성하는게 좋다.4) 테스트 간 독립성을 보장하자- 테스트간의 공유자원 사용하지 않기.- 테스트간의 독립성 보장하기~!5) 한 눈에 들어오는 Test Fixture 구성하기- Fixture : 고정룰, 고정되어 있는 물체- Test Fixture : 테스트를 위해 원하는 상태로 고정시킨 일련의 객체6) Test Fixture 클렌징- @Transactional, @rollback 방식과 deleteAllInBatch(), deleteAll() 등을 잘 알고 사용해야 한다.7) @ParameterizedTest8) @DynamicTest9) 테스트 수행도 비용이다. 환경 통합하기- @DataJPATest 보다 @SpringbootTest 사용을 권장한다.- 컨트롤러(통합) 테스트시 @WebMvcTest의 Controllers 옵션을 통해 특정 컨트롤러들만 지정하여 테스트해줌으로써 테스트 수행 비용을 줄여준다.10) private 메서드는 테스트할 필요가 없다.11) 테스트에서만 필요한 메서드 중 생성자 등은 프로덕션 코드에 생성해도 좋다..Section9) AppendIx1) 학습 테스트- 잘 모르는 기능, 라이브러리, 프레임워크를 학습하기 위해 작성하는 테스트- 여러 테스트 케이스를 스스로 정의하고 검증하는 과정을 통해 보다 구체적인 동작과 기능을 학습할 수 있다.- 관련 문서만 읽는 것보다 훨씬 재미있게 학습할 수 있다.2) Spring Rest Docs- 테스트 코드를 통한 API 문서 자동화 도구- API 명세를 문서로 만들고 외부에 제공함으로써 협업을 원활하게 한다.- 장점→ 테스트를 통과해야 문서가 만들어진다 (신뢰도가 높다)→ 프로덕션 코드에 비침투적이다.- 단점→ 코드 양이 많다.→ 설정이 어렵다..Day-15 Mission) 레이어드 아키텍처에서의 테스트 코드 작성강의로 배운 레이어드 아키텍처 관련 내용을 확장시켜 정리할 수 있어 좋았다.과제 Link.Day-18 Mission) Test Double 어노테이션 이해 및 테스트 항목 배치@Mock, @MockBean, @Spy, @SpyBean, @InjectMocks의 차이점을 정리하고 given-when-then 전략으로 테스트 코드 배치 방법을 고민해 볼 수 있어 좋았다.과제 Link..회고오늘로써 인프런 워밍업 클럽 스터디 2기 대장정이 마무리 되었다.클린코드와 테스트코드는 누구나 중요성을 알지만, 혼자서 공부하기 쉽지 않은 부분이다.강의를 완벽하게 이해하지는 못했지만, 강의를 통해 Clean Code와 Test Code에 한 발자국 더 다가갈 수 있었고, 실무에도 점차적으로 적용 해보면서 뜻 깊은 경험을 할 수 있었다.다음에 인프런 스터디 3기가 열린다면 재참여를 고려해 봐야겠다마지막으로 강의와 스터디를 만들어주신 박우빈님과 스터디 관리에 힘써주신 셰리 매니저님께 감사의 마음을 전합니다..출처https://inf.run/zgJk5https://inf.run/kHiWM

백엔드워밍업클럽테스트코드

[워밍업 클럽 2기 BE 클린코드 & 테스트] Mission Day18

 Practical Testing: 실용적인 테스트 가이드를 수강하고 진행한 미션입니다. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다.@MockMockito에서 제공하는 어노테이션스프링 컨텍스트 없이 단위 테스트 가능가짜 객체를 생성, 모든 메소드는 기본적으로 아무 동작도 하지 않음 -> Stubbing 필요@MockBeanSpring Boot Test에서 제공하는 어노테이션스프링이 mock 객체를 주입 -> 주로 통합테스트에 사용스프링 빈을 mock 객체로 대체할 때 사용@SpyMockito에서 제공하는 어노테이션스프링 컨텍스트 없이 단위 테스트 가능실제 객체를 사용실제 객체를 부분적으로 mock할 때 사용mock하지 않은 메소드는 실제 객체의 메소드가 동작함@SpyBeanSpring Boot Test에서 제공하는 어노테이션스프링이 spy 객체를 주입 -> 주로 통합테스트에 사용스프링 빈을 spy 객체로 대체할 때 사용 -> 실제 객체를 감싸서 일부 기능만 mock@InjectMocksMockito에서 제공하는 어노테이션@Mock이나 @Spy 등으로 생성된 객체를 주입시킴주로 테스트 대상 클래스의 의존성을 주입할 때 사용 아래 3개의 테스트가 있습니다. 내용을 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요? (@BeforeEach에 올라간 내용은 공통 항목으로 합칠 수 있습니다. ex. 1-1과 2-1을 하나로 합쳐서 @BeforeEach에 배치)요구 사항게시판 게시물에 달리는 댓글을 담당하는 Service Test댓글을 달기 위해서는 게시물과 사용자가 필요하다.게시물을 올리기 위해서는 사용자가 필요하다.@BeforeEach void setUp() { ❓ } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 1-6. 댓글 생성 // given ❓ // when ❓ // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 2-7. 댓글 수정 // given ❓ // when ❓ // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 3-9. 사용자2가 사용자1의 댓글 수정 시도 // given ❓ // when ❓ // then 검증 } RefactoringFixture에 부분을 최대한 보수적인 관점으로 대했다. 꼭 필요한 부분만 BeforeEach 절에 담으려고 했고, 애매한 부분은 각 테스트 내에 담았다."자신이 작성한 댓글이 아니면 수정할 수 없다." 부분이 애매하다고 느꼈다. 검증 단계에서 서로 다른 사용자라는 부분을 추출해서 보여줄 여지가 있다고 생각해 해당 테스트 내에 다 담았다. 구체적인 로직이 있으면 검증에 영향이 가지 않고, 다른 테스트에서도 공통적으로 사용되는 부분이 있으면 setUp으로 이관해도 좋다고 생각한다.@BeforeEach void setUp() { 사용자 생성에 필요한 내용 준비 게시물 생성에 필요한 내용 준비 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 사용자 생성 게시물 생성 댓글 생성에 필요한 내용 준비 // when 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 사용자 생성 게시물 생성 댓글 생성에 필요한 내용 준비 댓글 생성 // when 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 사용자1 생성에 필요한 내용 준비 사용자1 생성 사용자2 생성에 필요한 내용 준비 사용자2 생성 사용자1의 게시물 생성에 필요한 내용 준비 사용자1의 게시물 생성 사용자1의 댓글 생성에 필요한 내용 준비 사용자1의 댓글 생성 // when 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }

빠타박스

[인프런 워밍업클럽 2기] CS전공지식_Special Mission [한번 풀어보기]

결석한 적은 없는 그냥 풀이가 보이길래 한번 풀어보자 생각했다. 하지만 잘 못 건드렸다.. 난 아직도 실력이 더 필요하구나.. 어렵다. 이거 푼다고 map 알아보다가. map은 기본적으로 오름차순 정렬되어버려서. 의미가 없었다...퀵정렬로 풀라고 했으니까. .일단.. 알아보다 도저히 안되서.. 어떻게 해야하지 하다가.  그냥 알아보았다..;; 졸기를 반복하다가... 쩝... 특별미션특별 미션)  실수로 워밍업 클럽 출석을 빼먹었는데 우연히 데이터를 수정할 수 있는 권한이 주어졌습니다. 러너분의 이름(name)과 출석수(count)가 저장된 배열에서 여러분(나)의 데이터를 퀵정렬을 이용해 오름차순 정렬하고 가장 첫 번째 데이터인 여러분의 출석수를 변경하도록 코드를 작성해주세요. (퀵정렬 구현 부분도 변경)문제// 퀵소트 구현 부분...(생략) let user1 = { name: "홍길동", count: 5 }; let user2 = { name: "임꺽정", count: 4 } let user3 = { name: "이순신", count: 3 } let user4 = { name: "나", count: 1 } let user5 = { name: "짱구", count: 5 } let arr = [user1, user2, user3, user4, user5] console.log("===== 정렬 전 ====="); console.log(arr); quickSort(arr, 0, arr.length - 1); console.log("===== 정렬 후 ====="); console.log(arr);[예상 결과] ===== 정렬 전 ===== [ { name: '홍길동', count: 5 }, { name: '임꺽정', count: 4 }, { name: '이순신', count: 3 }, { name: '나', count: 1 }, { name: '짱구', count: 5 } ] ===== 정렬 후 ===== [ { name: '나', count: 5 }, { name: '이순신', count: 3 }, { name: '임꺽정', count: 4 }, { name: '홍길동', count: 5 }, { name: '짱구', count: 5 } ] 처음 풀었던 미친방식... #include <iostream> #include <algorithm> #include <map> #include <vector> using namespace std; /*map은 기본적으로 키를 기준으로 오름차순한다. */ struct Student { char name[20]; int count; map<string, int> m = { {"홍길동", 5}, {"임꺽정", 4}, {"이순신", 3}, {"나", 1}, {"짱구", 5}}; map<string, int>::iterator miter; }; // 오름차순 정렬을 위한 static bool cmp(const pair<string, int>& a, const pair<string, int>& b) { if (a.second == b.second) return a.first > b.first; return a.second < b.second; } int main() { struct Student s; // vector<pair<string,int>> v(s.m.begin(), s.m.end()); // 구조체 안에 있는 map으로 호출 for (s.miter = s.m.begin(); s.miter != s.m.end(); ++s.miter) { cout << s.miter->first << ' ' << s.miter->second << endl; } cout << endl; // sort(v.begin(), v.end(), cmp); s.m["나"] = 5; // vector 선언된 map 형식을 가져온다. for (s.miter = s.m.begin(); s.miter != s.m.end(); ++s.miter) { cout << s.miter->first << ' ' << s.miter->second << endl; } return 0; }  #include <iostream> #include <vector> #include <string> using namespace std; // 사용자 정보를 나타내는 구조체 struct User { string name; int count; }; // 퀵소트 함수 정의 void quickSort(vector<User>& arr, int left, int right) { if (left < right) { int pivotIndex = partition(arr, left, right); quickSort(arr, left, pivotIndex - 1); quickSort(arr, pivotIndex + 1, right); } } // 분할 함수 정의 int partition(vector<User>& arr, int left, int right) { int pivot = arr[right].count; // 피벗을 오른쪽 끝 요소의 count로 설정 int i = left - 1; // i는 피벗보다 작은 요소의 마지막 인덱스 for (int j = left; j < right; j++) { // 현재 요소가 피벗보다 작거나 같은 경우 if (arr[j].count < pivot || (arr[j].count == pivot && arr[j].name < arr[right].name)) { i++; swap(arr[i], arr[j]); // i와 j 요소를 교환 } } swap(arr[i + 1], arr[right]); // 피벗을 올바른 위치로 이동 return i + 1; // 피벗의 최종 위치 반환 } int main() { // 사용자 객체 초기화 User user1 = { "홍길동", 5 }; User user2 = { "임꺽정", 4 }; User user3 = { "이순신", 3 }; User user4 = { "나", 1 }; User user5 = { "짱구", 5 }; // 사용자 객체를 담을 벡터 vector<User> arr = { user1, user2, user3, user4, user5 }; cout << "===== 정렬 전 =====" << endl; for (auto& user : arr) { cout << "이름: " << user.name << ", count: " << user.count << endl; } // 퀵소트 호출 quickSort(arr, 0, arr.size() - 1); cout << "===== 정렬 후 =====" << endl; for (auto& user : arr) { if (user.name == "나") { user.count = 5; } cout << "이름: " << user.name << ", count: " << user.count << endl; } return 0; }

알고리즘 · 자료구조자료구조알고리즘cs-미션-발자국인프런워밍업클럽

zooxop

인프런 워밍업 스터디 클럽 2기 백엔드(클린코드&테스트코드) Day 18 미션

인프런 워밍업 클럽 2기, 백엔드(클린코드&테스트코드) 과정에 참여하고 있습니다.이번 글은 Day 18 미션 제출을 위해 작성하였습니다.[미션 내용]@Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다.미션에서 제공된 예제를 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치해보기 강의 링크: Readable Code: 읽기 좋은 코드를 작성하는 사고법 1. Test Double Annotations 특징@Mock실제 객체 대신 가짜 객체를 생성한다.기본적으로 모든 메서드가 아무런 동작도 하지 않음.when() 을 통해 특정 메서드의 동작과 결과값을 임의로 지정할 수 있음.Spring context 의존 X.@Mock private UserService userService; // 사용 예시 when(userService.findById(1L)).thenReturn(new User());@MockBean기본적으로 @Mock 과 유사하지만, Spring context에 의존한다.Spring context에 Mock 객체를 Bean으로 등록함.같은 타입의 기존 Bean을 찾아서 Mock으로 교체하는 방식통합 테스트에서 특정 Bean만 Mock으로 대체하고 싶을 때 유용함.@MockBean private UserService userService; @Spy실제 객체를 생성하고 일부 메서드만 Mock으로 지정할 수 있음.명시적으로 지정하지 않은 메서드는 실제 동작을 수행한다.일부 메서드만 수정하고 싶을 때 유용함.@Spy private UserService userService; // 특정 메서드만 Mock 처리 doReturn(new User()).when(userService).findById(1L);@SpyBean기본적으로 @Spy 와 유사하지만, Spring context에 의존한다.Spring context의 실제 Bean을 Spy로 감싸서 사용함.실제 Bean 의 일부 동작만 수정하고 싶을 때 유용함. @SpyBean private UserService userService;@InjectMocksSpring context 의존 없이(통합 테스트 없이) 의존성 주입이 필요한 클래스(ex. Service class)를 테스트할 때 유용하다.@Mock 이나 @Spy로 생성된 객체를 자동으로 주입받도록 해준다.@Mock private UserRepository userRepository; @InjectMocks private UserService userService; // userRepository가 자동 주입됨 주요 차이점통합 테스트 필요 여부 차이필요: @MockBean, @SpyBean불필요: @Mock, @Spy, @InjectMocks동작 방식완전한 가짜 객체: @Mock, @MockBean실제 객체를 부분적으로 Mocking: @Spy, @SpyBean  @BeforeEach, given절, when절에 배치해보기@BeforeEach void setUp() { (1-1., 2-1., 3-1) 사용자1 생성에 필요한 내용 준비 (1-2., 2-2., 3-2) 사용자1 생성 (1-3., 2-3., 3-5) 사용자1의 게시물 생성에 필요한 내용 준비 (1-4., 2-4., 3-6) 사용자1의 게시물 생성 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 } 

백엔드워밍업클럽백엔드클린코드테스트코드미션

gotjd9773

[인프런 워밍업 클럽 스터디 2기 백엔드] 4주차 발자국

개요4주차 종료!Practical Testing 실용적인 테스팅 가이드를 완강 했다!인프런 워밍업 클럽 스터디 2기 백엔드 과정... 이것으로 끝!감격스럽다.4주차 공부한 내용권장 진도표에 맞게 진도를 나갔네? 배운 것들1. MockitoMockito 라이브러리를 써봤지만, 사용할 때마다 찝찝한 느낌을 갖고 사용해왔다.이번 주차에 강의를 학습하며 Mockito를 언제 쓰면 좋은지 @MockBean 과 @Mock 의 차이는 무엇인지를 제대로 알 수 있었다. 2. Classicist vs Mockist우빈님은 Classicist 인데, 강의를 들어보니 나도 Classicist가 되었다.정답이 있는 문제는 아니라 상황에 맞게 적절히 Mocking 할 땐 하고, 통합 테스트할 땐 하고 하면 될 듯 하다. 3. Test Fixture 가이드라인다른 강의에서 Fixture를 하나의 클래스로 관리하라고 배웠었다.그래서 그렇게 사용해왔는데, 문제는 원하는 필드를 지정해주고 싶을 때마다 Fixture를 생성하는 메서드가 증가하게 되고,메서드가 증가하면 관리가 너무 어려워지곤 했다. 더군다나 큰 프로젝트 같은 경우 엔티티당 필드가 수 십개가 넘어가는 게 대부분 인데, 이걸 전부 하나의 클래스로 관리하는 건 별로 좋은 방법 같지는 않다.  강의를 통해서 Test Fixture를 어떻게 생성하는 지, 어떻게 생성 메서드를 관리하는 지 배울 수 있었다.  4. 테스트 환경 통합하기테스트 환경을 통합해야 한다는 개념 자체를 몰랐다. 이런 게 가능할 거라 생각도 못했던 것 같다. 강의 들으면서 조금 충격을 받았다. 5. private 메서드를 테스트하고 싶은가? 그러면 책임 분리를 고민해봐라이것도 충격! private 메서드를 테스트하지 말라고 하시는 말씀에"그렇구나, 테스트 안 해도 되네? 개꿀!" 이렇게 생각하며 설렁설렁 듣고 있었는데,private 메서드를 새로운 객체에 public 메서드로 빼놓고 객체간 협력하게 하는 코드를 작성하시는 모습이 인상적이었다.테스트 생각을 많이 하다 보면 자연스레 객체지향에 가까워질 수도 있음을 깨달았다. 6. 학습테스트프로젝트에 쓰고 싶은 새로운 라이브러리를 테스트로 학습하는 건 정말 좋은 방법인 것 같다. 7. Spring REST docsSwagger만 사용해봤는데 Spring REST docs는 들어는 봤지, 이번에 처음 사용해봤다.설정하는 게 어렵긴 한데, 실무에서 많이 쓰인다고 하니 이번에 경험해볼 수 있어서 좋았다. 미션이번 주차에는 Day 15. 미션, Day 18. 미션이 있었다. Day 15. 미션 - Layered Test 작성법 자기만의 언어로 정리하기배운 내용을 다시 한 번 정리하는 거라 어렵진 않았다.https://zircon-neptune-a7d.notion.site/Day-15-Layered-test-124ba1f1340980ddb599f68747a2ddfe?pvs=4 Day 18. 미션 Day 18. 미션 - 1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks의 차이 정리하기역시 배운 내용을 다시 한 번 정리하는 거라 어렵진 않았다.https://zircon-neptune-a7d.notion.site/Day-18-129ba1f134098015983ade0586420ed1?pvs=4 Day 18. 미션 - 2. 수도 코드로 작성된 테스트 3개의 코드를 재배치하기제시된 수도 코드@BeforeEach void setUp() { ❓ } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 1-6. 댓글 생성 // given ❓ // when ❓ // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 2-7. 댓글 수정 // given ❓ // when ❓ // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 3-9. 사용자2가 사용자1의 댓글 수정 시도 // given ❓ // when ❓ // then 검증 }제시된 수도 코드는 중복이 많아 보인다. 깔끔하게 정리해보는 미션이었다.내가 재배치한 결과는 아래와 같다.@BeforeEach void setUp() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when & then --> 예외 발생 3-9. 사용자2가 사용자1의 댓글 수정 시도 } 끝! 4주간 알차게 학습했다.미션과 발자국, 두 개 강의 모두 100% 학습해서 뿌듯하다.인프런 워밍업 클럽 스터디 GOOD!  

백엔드테스트Junit5MockitoSpringRestDocs

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 day18 과제

강의 : Practical Testing: 실용적인 테스트 가이드@Mock 객체가 기대하는 행위와 리턴 값을 지정하여 테스트에서 기대하는 동작만 테스트가 가능하다주로 외부 네트워크를 사용하는 객체에 사용하면 좋다 @MockBean스프링 컨테이너에서 사용하기 위한 @Mock 객체@Spy 일부는 Mock 객체처럼 동작만 그 이외에는 실제 객체처럼 동작한다내가 지정한 동작을 기대하는 행위, 반환에 대한 mocking 할 수 있다실제로 많이 쓰이지는 않는다 @SpyBean 스프링 컨테이너에서 사용하기 위한 @Spy 객체@InjectMocksMock, MockBean 객체를 주입 받는 대상 객체에 사용된다ex) OrderService에 UserService, ProductService 주입이 필요한 경우 @MockBean private UserService userService; @MockBean private ProductService productService @InjectMocks private OrderService orderService;각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치할지?@BeforeEach void setUp() { 사용자 생성에 필요한 내용 준비 게시물 생성에 필요한 내용 준비 댓글 생성에 필요한 내용 준비 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-2. 사용자 생성 1-4. 게시물 생성 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-2. 사용자 생성 2-4. 게시물 생성 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-2. 사용자1 생성 3-4. 사용자2 생성 3-6. 사용자1의 게시물 생성 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }

백엔드워밍업클럽2기클린코드&테스트

[인프런-워밍업클럽 BE 2기] Day 18 미션

1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이@Mock타겟 객체의 껍데기를 생성다른 객체에 의존성을 주입하려면 해당 객체에 @InjectMocks 필요@MockBean껍데기를 Bean으로 등록테스트 클래스에 @SpringBootTest, 주입 대상에 @Autowired 필요@Spy객체의 기능 일부만 stub하고 나머지는 실제 기능 호출@SpyBean@Spy Bean으로 등록테스트 클래스에 @SpringBootTest, 주입 대상에 @Autowired 필요@SpyBean 대상이 인터페이스인 경우 구현체가 스프링 컨텍스트에 등록되어있어야함@InjectMocks@SpringBootTest가 아닌 경우 @Mock, @Spy 설정된 객체를 타겟 객체에 주입 2. 아래 3개의 테스트가 있습니다. 내용을 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요? (@BeforeEach에 올라간 내용은 공통 항목으로 합칠 수 있습니다. ex. 1-1과 2-1을 하나로 합쳐서 @BeforeEach에 배치)@BeforeEach void setUp() { beforeEach-1. 사용자1 생성에 필요한 내용 준비 beforeEach-2. 사용자1 생성 beforeEach-3. 사용자2 생성에 필요한 내용 준비 beforeEach-4. 사용자2 생성 beforeEach-5. 사용자1의 게시물 생성에 필요한 내용 준비 beforeEach-6. 사용자1의 게시물 생성 beforeEach-7. 사용자1의 댓글 생성에 필요한 내용 준비 beforeEach-8. 사용자1의 댓글 생성 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 활용 - beforeEach-2. 사용자1 생성 활용 - beforeEach-6. 사용자1의 게시물 생성 1-1. 댓글 생성에 필요한 내용 준비 // given 1-2. 댓글 생성 // when // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { 활용 - beforeEach-2. 사용자1 생성 활용 - beforeEach-8. 사용자1의 댓글 생성 // given 2-7. 댓글 수정 // when // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 활용 - beforeEach-4. 사용자2 생성 활용 - beforeEach-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }

wisehero

[인프런-워밍업클럽 BE 2기] Day18 과제

1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다. 모두 JUnit, Spring 테스트 환경에서 사용된다. 각각의 어노테이션들은 그 목적과 사용 방식이 조금은 다르다. @Mock가짜 클래스 객체를 생성한다. 이 어노테이션에 의해 모킹된 객체는 실제 객체의 메소드 호출에 대해 빈 응답을 준다.외부 의존성을 최소화 해줄 수 있어서 단위 테스트를 작성할 때 유용하다. 실제 객체의 메소드를 호출하지 않으니당연히 실체 객체를 생성하는 것도 아니다. @MockBeanSpringBoot에서 제공하는 어노테이션이고 Spring 애플리케이션의 컨텍스트에서 관리하는 빈을 모킹한다.@Mock은 스프링 컨텍스트와 관련이 없지만 @MockBean은 스프링 컨텍스트와 관련이 있다. 특정 빈을 모킹된 객체로대체할 때 사용된다. 주로 통합 테스트에서 다른 빈과의 의존성을 모킹할 때 유용하다. @Spy스파이 객체는 실제 객체의 메소드 호출을 그대로 유지한다. 특정 메소드를 모킹할 수 있는데 일부 메소드는 실제로 호출되게하고일부 메소드는 모킹할 수 있다.  @SpyBean@MockBean과 마찬가지로 스프링 애플리케이션 컨텍스트에서 관리하는 빈을 스파이한다. @InjectMocksInject라는 말에서 알 수 있듯이 의존성 주입을 도와주는 어노테이션이다. @Mock이나 @Spy를 명시한 클래스들을@InjectMocks라는 어노테이션이 달린 대상 클래스에 의존성을 주입해준다. 주로 단위테스트에서 사용된다.  "@BeforeEach void setUp() { 1-1. 사용자1 생성에 필요한 내용 준비 1-2. 사용자1 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 } @DisplayName(""사용자가 댓글을 작성할 수 있다."") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName(""자신이 작성한 댓글이 아니면 수정할 수 없다."") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }" 

백엔드백엔드워밍업클럽클린코드테스트

예진안

인프런 워밍업 클럽2 cs <day14> 끝!

드디어 마지막 복습 ㅜㅜ 하라고 할 때 안해서 이번주 수요일까지 숙제가 생겨버렸다..할 때 하자... 시간 더들이지말고알고리즘동적프로그래밍 - 메모이제이션앞서 재귀식을 배웠다. 재귀식은 콜스택에 함수를 계속해서 쌓고쌓고 하는 방식이였다.=> 자리차지하고 비효율적이다. 피보나치 수열을 이용해서 재귀식에서 상향식으로 효율적이고 빠르게 연산하는 방식을 알아보려고한다.피보나치 수열 : 첫번째 수와 두번째 수를 더해 세번째 수를 만들고 두번째 수와 세번째 수를 더해 네번째 수를 만든다. 이렇게 무한하게 배열을 이룰 수 있는 수열이다.피보나치 수열을 재귀식으로 만들어보자function fibo1(n){ if(n==0||n==1) return n; return fibo1(n-2) + fibo1(n-1); }그림으로 쉽게 배우는 알고리즘 - 감자하지만 수가 커지면 커질수로 중복되는 계산도 많아진다. 아래와 같이 초록색은 계산중인 부분, 노란색은 중복이 되는 부분이다.=> 효율성이 떨어진다. 이런 효율성을 보완하기 위해 메모이제이션을 사용하게 된다.메모이제이션 : 계산을 저장해서 같은 방식의 계산을 방지한다. 계산했을 때 저장되어있지않으면 그 결과를 저장한다. -> 해시테이블 이용해서 key는 계산하고자 하는 데이터, value는 결과를 저장한다. - 재귀식으로 인해서 중복 계산이 많은 것을 결과를 저장하는 방식으로 단점을 해소했다. 역시 메모이제이션도 재귀식이다.function fibo2(n, memo){ k if(n==0||n==1) return n; if(memo[n] == null) { memo[n] = fibo2(n - 2, memo) + fibo2(n - 1, memo);// value 결과를 저장 //이런 식으로 값을 만들어서 결과값을 나타내기 때문에 그냥 함수에 변수 넣은 게아니다. } return memo[n]; }재귀식 vs 메모이제이션재귀식 : 재귀만을 사용해서 중복되는 것들이 있다.메모이제이션 : 검색하고 없으면 저장하여 결과값 동적프로그래밍 - 타뷸레이션타뷸레이션 : 메모이제이션도 재귀식보다는 효율적이지만, 하나의 함수만 호출하는 것보다는 비효율적이였다. 타뷸레이션은 상향식을 이용해서 하나의 함수만 호출해서 값을 얻을 수있다. 이 때 객체를 만들어서 해시테이블처럼 이용해서 계산에 필요한 모든 값들을 저장해놓고 꺼내 쓸 수있도록한다.상향식방식의 피보나치 수열 구하긔function fibo3(n){ if(n<=1) return n; let table =[0,1]; for(let i=2; i<=n; i++){ table[i] =table[i-2] + table[i-1]; } return table[n]; }재귀식(O(n^2))< 메모이제이션(O(n))<=타뷸레이션(O(n)) 메모이제이션은 메모리를 사용해 성능을 향상시킬 수있다.동적 프로그래밍이 필요한 분할 정복 문제를 풀 때 상황에 따라 다르겠지만 다루기 어려운 메모리는 재귀식으로 쉽게 해결할 때가 있다.메모이제이션을 사용해야할 때는 - 재귀식으로 직관적으로 해결할 수 있는 메모리를 하향식으로 해결하고 더많은 메모리를 이용해서 성능을 향상시킨다.타뷸레이션을 사용하기 적할 할 때는 - 재귀가 직관적이지 않을 경우 상향식인 타뷸레이션으로 접근한다.아니 알고리즘 방금했는데 메모이제이션이랑 타뷸레이션 특성을 헷갈려함 빡대가리니 그렇게 달달 외울라고 하니까 이게 이거였나? 하고 헷갈리지 진짜 어이가 없네. 메모이제이션어캐쓰게됐는지 그래서 기존보다 어떤게 나아졌고 뭐는 나빠졌으며 하면서 이어져야되는데 특성! 외우고 아 이게 메모이제이션이엿나,, 이 특성이 타뷸레이션이였나? 이러니까 머리에 안들어오지운영체제파일과 파일 시스템파일을 사용자가 저장하려고 할 때 운영체제를 거쳐서 하드디스크에 저장된다. 파일 시스템 (=운영체제) : 운영체제가 파일을 관리하기위해 만듦 파일엔 파일테이블이 있는데 페이지테이블은 비슷하다.파일 시스템의 기능 파일과 디렉토리 생성/수정/삭제, 파일권한관리 - 다중 사용자 기능을 지원하는 요즘 다른 사용자로부터 파일 보호를 위해서이다. 무결성 보장 - 파일의 내용이 손상되지 않도록한다. 백업과 복구 암호화주변 장치( 캐릭터와 블록으로 전송단위를 나눌 수있다)파일 시스템은 하드디스크나 flash memory(보조기억장치)에 저장되기 때문에 전송단위는 블록이다.사용자는 바이트 단위로 접근, 파일관리자가 중간에서 변환해준다.뒤에 확장자를 붙여 (.exe, .txt)확장자에 알맞는 프로그램을 실행시켜 파일을 본다. (사진-포토샵, 텍스트 파일 - 메모장 ..)파일은 헤더와 데이터로 이뤄져있다. 파일의 헤더는 파일의 속성들이 저장되어있다.파일제어 블록(File Control Block) : 파일 관리를 위해 정보를 저장 해놓은 블록이다. 파일 디스크립터라고도 부르고 파일마다 존재한다. 저장장치에 저장되어있다가 파일이 오픈 시 메모리로 이동된다. 파일 시스템이 파일 디스크립터를 관리한다.사용자는 파일을 파일 시스템이 메모리에 건내준 파일 디스크립터를 이용해서 파일을 볼 수있다.4번째 줄 코드에서 open()했을 때 파일디스크립터,fd를 메모리에 이동시켰다. 5번째 줄 close()fd를 참조해 파일을 안전하게 닫았다. 파일은 데이터의 집합이다.데이터 집합이 어떻게 이뤄지는지에 따라 종류를 나눌 수있다.순차파일 구조 : 파일의 내용이 연속적으로 이어진 상태 (카세트 테이프) 파일디스크립터를 사용해서 처음부터 순차적으로 데이터를 확인할 수있다. lseek()함수를 이용해 보고자 하는 데이터의 위치로 파일 디스크립터 위치를 옮긴다. - 장점 : 순차적 기록, 단순 구조. 단편화 현상없음 - 단점 : 특정지점으로 이동 어려움. 데이터 삽입,삭제,탐색에 시간이 많이 걸린다. lseek(fd, 10,SEEK_CUR);// 현재 위치에서 10번 앞으로 파일디스크립터를 이동시킨다.직접파일 구조 : 저장하려는 데이터를 해시함수로 저장위치를 정한다. - hashTable 자료구조를 이용하고 요즘 사용이 많은 .JSON에서 사용한다. - 해시함수처럼 한번에 데이터를 찾을 수있지만 공간낭비가 있을 수있다.인덱스파일구조 : 순차접근 +직접파일접근 장점 데리고왔다~ - 순서대로 접근도 할 수 있고 직접 파일에 접근도 할 수있다.인덱스 테이블을 만들어서 노래를 클릭했을 때 순차적인 데이터를 참조해서 바로 노래를 들을 수있고순차데이터를 이용해서 노래재생을 해 순차적으로 노래를 들을 수 있다.디렉토리파일의 파일. 파일들을 모아둔 파일들관련있는 파일들을 모아둔다.루트디렉토리와 자식디렉토리가 존재한다.유닉스와 리눅스는 루트디렉토리를 /로, 경로도 / 로 표시한다. 원도우는 루트디렉토리를 c:으로 디렉토리와 디렉토리 경계구분은 \ 로 구분한다.디렉토리는 파일과 같은 구조이다. 파일은 데이터가, 디렉토리는 파일 정보가 저장되어있다.디렉토리도 헤드가 있다! 루트 디렉토리 헤더 : 디렉토리 정보가 시작하는 위치를 가리키고 000디렉토리 헤더 는 해당 프로그램의 정보가 시작하는 위치를 가리킨다.루트디렉토리는 상위 디렉토리가 없어서 ..은 본인을 나타낸다.디렉토리 구조 초기 파일 시스템의 디렉토리는 루트디렉토리에만 디렉토리가 존재해서 단순했다.-> 파일들이 많아지면서 다단계 디렉토리가 생겼다. 일반 디렉토리에서 하위 디렉토리를 만들수 있는 트리구조가 되었다.바로가기 기능때문에 운영체제는 트리구조에서 순환이 생긴다. 파일과 디스크파일시스템은 메모리와 비슷하게 일정한 크기로 나누고 나눈 공간을 블록이라 부른다. 메모리에선 페이지!한블록을 1~8KB 로 쪼갠다. 파일 제어 테이블 : 파일이 시작하는 블록의 위치 정보도 담고 있다.하나의 파일은 여러 개의 블록으로 이뤄져있고 어떻게 블록을 잇느냐에 따라연속할당과 불연속할당으로 나눌 수 있다.연속할당 : 블록들을 디스크에 연속적으로 저장한다. 파일 시작블록만 알면 모든 데이터를 접근할 수 있다.불연속할당 : 비어있는 디스크 공간에 데이터를 분산시켜서 저장하는 방식이다. 분산된 블록은 파일 시스템이 관리불연속할당의 연결할당 : 자료구조의 연결리스트방식 NULL을 만날 때까지 데이터를 참조해 모든 데이터를 얻을 수 있다.불연속할당의 인덱스 할당테이블의 블록포인터가 데이터 블록에 직접연결이 아닌 데이터들의 인덱스를 가지고 있는 인덱스 블록을 연결한다. 이 인덱스블록은 파일 테이블의 블록포인터가 가리키게된다.찾는 것이 블록이아니고 나는 데이터 0,3,4번이 필요해 했을 때 어떤 인덱스를 참조해야되지?하고 찾는것같다.파일 c를 찾을래 위치는1 이구나 그럼 1번 블록으로 ..가 아니고인덱스 블록에 있는 0,3,4번블록을 참조하면 데이터를 모두 찾을 수있다.인덱스 할당은 데이터가 많아 테이블이 꽉 찬 경우 인덱스 블록을 더 만들어 연결해 테이블 확장에 용이하다.  이해가 안가는데 왜 데이터블록이랑 인덱스블록이랑 똑같이 해놨음? 그럼 파일 B는 어캐 인덱스블록에 연결하나?디스크의 크기디스크의 블록 수를 잘게 자를 수록 공간을 낭비없이 사용가능하지만 각자 신경쓸 블록이 많아진다. 또 디스크를 크게 자를 경우 내부단편화가 생겨 낭비가 생긴다.->그럼 디스크의 빈공간을 찾아야되나? 그럼 처음부터 끝까지 메모리를 뒤져 빈 공간을 확인해야하므로 비효율적이다. free Block list로 이문제를 해결했다.Free Block List : 디스크의 빈공간을 모아둔 리스트. - 그럼 데이터 삭제하면 free block list로 가겠군녀=> 특정파일 삭제시 실제 모든 데이터를 지우는 게아니고 파일 테이블의 헤더를 삭제하고 블럭을 free block list에 추가한다.사용했던 블럭의 데이터는 여전히 남아 포렌식을 이용해 복구하면 데이터 사용이 가능하다.ex) a파일을 지웠는데 파일에 해당하는 4, 11, 14 블록은 리스트에 올라간다. = a파일에 해당하는 블록은 4,11,14블록으로 흩어져있다.복습할 때 시간이 정말 많이 걸린다. 하루 수업을 두시간동안 복습한거같다. 왤캐 오래걸리지...흑흑 

알고리즘 · 자료구조

ykm8864

[인프런 워밍업 클럽 2기] Layered Architecture에서의 Testing 정리

Layered Architecture의 레이어별 특징 및 테스팅 방법 정리예시: 음식 배달 서비스각 레이어를 음식 배달 서비스의 역할로 설명한다. 음식 배달 서비스를 통해 사용자가 음식을 주문하고, 음식점에서 음식을 준비하고, 배달원이 고객에게 음식을 전달하는 과정을 생각해 본다. Persistence Layer특징비지니스 가공 로직이 포함되어서는 안 된다.이 레이어는 데이터베이스와 상호작용하여 음식점의 메뉴, 고객 정보, 주문 기록 등을 저장하고 관리한다. 마치 식당의 재료 창고처럼, 데이터의 상태를 정확히 관리하고 필요한 정보를 보관한다. 창고에서는 식당의 주방장이 재료를 요청하면, 정확한 재료를 꺼내주는 역할을 한다. 데이터의 가공은 하지 않고, 필요한 데이터만 정확하게 주고받는 것이 이 레이어의 역할이다.테스트 방법- 단위 테스트: 재료 창고에서 특정 재료를 꺼내거나, 새로운 재료를 추가할 때 그 과정이 제대로 이루어지는지 검증한다. Mocking을 통해 창고에 직접 접근하지 않고, 데이터가 올바르게 반환되는지 확인한다.- 통합 테스트: 실제 창고에서 재료를 꺼내고 추가하는 테스트를 진행한다. 예를 들어, '김치 찌개 재료'를 창고에 추가하고, 해당 재료를 제대로 꺼낼 수 있는지를 확인한다. Business Layer특징트랜잭션을 보장해야 한다.이 레이어는 주방에서 음식의 조리 과정을 담당한다. 사용자 주문에 따라 어떤 메뉴를 어떻게 조리할지 결정하고, 레시피에 따라 재료를 가공하거나 조리 과정을 관리한다. 주방장은 여러 재료를 받아서 맛있는 요리를 만들어내는 역할을 한다. 마치 식당 주방장이 음식의 맛과 품질을 관리하듯, 비즈니스 로직을 통해 데이터와 요구사항을 처리한다.테스트 방법- 단위 테스트: 주방장이 다양한 재료로 요리를 만들 때 레시피에 따라 올바르게 조리하는지 검증한다. Mocking을 통해 창고에서 직접 재료를 받지 않고, 주방에서의 조리 과정 자체에 집중한다.- 통합 테스트: 주방과 창고가 함께 작동하며 올바른 음식을 내놓는지를 확인한다. 예를 들어, '된장찌개' 주문이 들어왔을 때 창고에서 된장과 야채를 받아, 조리 과정을 거쳐 최종 요리가 완성되는지를 검증한다. Presentation Layer특징MockMvc를 통해 내가 테스트하고자하는 부분에 집중한다.상위레이어가 하위 레이어를 알고 있는 것은 당연하지만, 하위레이어가 상위레이어를 알고 있는 것은 의존성이 강한 구조이다.이 레이어는 완성된 음식을 고객에게 전달하는 역할을 한다. 주로 배달원이 주문한 음식을 정확하게 고객에게 전달하며, 사용자가 원하는 방식대로 음식이 전달되는지 책임진다. 고객의 요구사항을 주방에 전달하고, 그 결과를 받아 다시 고객에게 전달하는 역할을 한다. 배달원이 고객에게 주문한 음식을 가져다주는 것처럼, 이 레이어는 사용자와 가장 가까운 곳에서 상호작용을 수행한다.테스트 방법- 단위 테스트: 배달원이 주문한 음식과 고객의 요청을 제대로 처리하는지 검증한다. Mocking을 통해 주방이나 창고에 접근하지 않고, 배달원과 사용자의 상호작용에 집중한다.- 통합 테스트: 배달원, 주방, 창고가 함께 작동하면서 사용자의 주문을 제대로 처리하는지 검증한다. 예를 들어, 고객이 '비빔밥'을 주문했을 때, 주방과 창고의 도움을 받아 배달원이 정확하게 비빔밥을 전달하는지를 확인한다. 흐름도사용자 <-> Presentation Layer (배달원 역할) <-> Business Layer (주방 역할) <-> Persistence Layer (재료 창고 역할)- 사용자(고객)는 Presentation Layer를 통해 주문을 요청한다.- Presentation Layer는 Business Layer에 주문 내용을 전달한다.- Business Layer는 Persistence Layer에서 필요한 데이터를 가져와 주문에 따라 데이터를 가공한다.- 최종적으로 Presentation Layer는 사용자가 원하는 형식으로 결과를 전달한다. - 각 레이어는 역할을 명확히 나누어, 서로에게 필요한 정보를 정확하게 전달하는 데 집중한다.

웹 개발워밍업클럼2기몰입하는개발자테스트코드TDD

도호

[인프런워밍업클럽2기] DAY 15 미션

MissionLayered Architecture 의 Layer 별 특징과 테스트 방법을 정리해보세요. Layered Architecture일반적으로 계층 구조 아키텍처는 3-Layered Architecture라고 해서 Presentation, Business, Persistence 3개의 레이어로 나누는 것이 일반적이다. 최근 DDD 바람이 불면서 Domain 레이어라고 4-Layered Architecture 바람이 불고 있는데 이는 논외로 하자.Presentation Layer외부 사용자와 통신을 담당하면서 Business Layer로 요청을 전달하고, 응답을 사용자에게 반환하는 역할을 담당한다.주로 외부 요청의 유효성 검증과 각 비즈니스 작업 결과를 사용자에게 정해진 포맷으로 내려주기 위한 포매팅 작업을 한다.만약 테스트를 한다면 MockMvc를 사용한 단위테스트, 아니면 통합 테스트를 해볼 수 있을 것이다.Business Layer어플리케이션의 비즈니스 기능을 처리한다. 서비스가 제공하는 기능의 실질적인 처리를 담당하며 트랜잭션을 적용할 수 있다. 그렇기 때문에 비즈니스 레이어의 작업 단위를 관심과 책임에 맞게 적절하게 분리하는 것이 중요하다.테스트를 진행한다면 Mockito를 사용해 단위 테스트를 진행할 수도 있고, 통합 테스트로 실제 DB 에서 조회해와서 처리하는 것을 확인할 수 있을 것이다.Persistence Layer데이터베이스 같은 저장 장치와 상호작용을 하는 부분이다. DAO, Repsitory라는 이름으로 불리기도 하였다. 이 계층에서는 비즈니스 로직이 들어가지 않도록 관리를 기울여야한다. 조회해온 정보를 비즈니스 레이어에 전달해주기 위해 가공처리를 하기도 한다.테스트를 진행한다면 통합테스트를 진행한다. 영속성 계층을 단위테스트 한다면 비즈니스 레이어에 전달해주기 위한 가공처리를 테스트 할 수 있을 것이다.

채널톡 아이콘