묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨스프링부트 JUnit 테스트 - 시큐리티를 활용한 Bank 애플리케이션
DummyObject 에 대하여
DummyObject 클래스의 newUser와 newMockUser 메서드 용도가 헷갈립니다..newMockUser 는 테스트할 때 Mock환경에서 User객체를 간편하게 만들기 위해 따로 만든 메서드인가요 ?newUser는 용도를 잘 모르겠어요
-
해결됨스프링부트 JUnit 테스트 - 시큐리티를 활용한 Bank 애플리케이션
DTO를 이너클래스로 계속추가하는 이유
bank.dto.user 패키지안에 req, resp 패키지를 만들어서 각각 DTO 클래스를 추가하는것과선생님이 하신 UserReqDto , UserRespDto 에 이너클래스로 추가하는건 무슨차이가 있나요 ???
-
해결됨스프링부트 JUnit 테스트 - 시큐리티를 활용한 Bank 애플리케이션
Builder 사용 궁금
제가 선생님 포토그램 강의를 들을 때는 엔티티클래스 위에 @Builder 어노테이션을 붙혔는데 이번강의에서는 엔티티클래스 내부에 생성자를 만들고 생성자메서드 위에 @Builder 어노테이션을 사용한 이유가 있을까요 ?
-
미해결Practical Testing: 실용적인 테스트 가이드
안녕하세요 강사님 컨트롤러 테스트 질문입니다!
좋은 강의를 찍어주셔서 너무 감사합니다.덕분에 테스트에 접근하는 방법을 터득할 수 있었습니다!컨트롤러 테스트는 Validation 역할이 핵심이라고 이해했는데,@Valid 어노테이션을 부착한 DTO 검증만 강의를 통해 배웠습니다. 궁금한게 있습니다.시큐리티를 적용했을 때 저는 컨트롤러 메서드 매개변수에 Authentication을 이용해서 SecurityContext 값을 사용하는데,이러한 SecurityContext도 검증을 해야 되는지,PathVariable에 대한 검증도 필요한가요?Param값 검증도 필요한지 궁금합니다.페이징했을 때 페이징 결과도 검증을 해야 될까요?Validation 영역이 아니라고 판단되어지는데, 강사님의 의견이 궁금합니다! 감사합니다.
-
미해결실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD
리뷰반영 강의에서 shortcut ctrl + esc 는 어떻게 설정하나요?
이 화면에서 단축키 ctrl + esc 만 누르면 시작 화면이 자꾸 떠서 단축키 등록이 안돼요..
-
미해결Practical Testing: 실용적인 테스트 가이드
Request Dto에서 생성자 관련...
강의에서 RequestDto를 Builder 패턴으로 생성자를 만들어주셨는데 그렇게 생성하신 이유가 있을까요?? 코드에서 확인해보면 이 생성자를 사용하지 않는걸로 확인이 되는데 .. 제가 추측하기로는 그 이후에 확장성을 위해서?,,, 라고 추측을 해봤는데 다른 이유가 있을까요????
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
List<Domain> -> List<Response> 변환을 Controller에서 하는 게 맞나요?
Domain -> Response 변환 코드를 Domain에 정의해두고Controller에서 Domain 메서드를 호출해서 Response를 변환하는게 맞나는 건 이해했습니다. 근데 실제 API에 해당 내용을 적용하려고 보니 Domain 단 건 조회보다는 List<Domain>을 반환하는 경우가 훨씬 많았습니다. 따라서 List<Domain>을 List<Response>로 변환해야 하는데 해당 작업을 for문이나 Stream으로 Controller로 처리하려니 Controller 코드도 지저분해지고 Controller가 하는 역할에 부합하지 않게 되는 것 같습니다.List<>를 변환할 때는 어디서 하는게 올바른 것인지 질문드립니다!
-
미해결스프링부트 JUnit 테스트 - 시큐리티를 활용한 Bank 애플리케이션
authenticationEntryPoint 질문
굳이 authenticationEntryPoint 에 들어갈 내용을 CustomREsponseUtil 로 빼는 이유가 무엇인가요 ??실무에서는 따로 뺄 만큼 들어가는 내용이 길어지나요 ? ?
-
미해결실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD
POJO
강사님이 생각하시는 POJO란 어떤 방법론인가요?? 시중에 나와있는 설명으로는 용어가 잘 와닿지 않아서요!!
-
미해결따라하며 배우는 리액트 테스트 [2023.11 업데이트]
test was not wrapped in act관련 질문
안녕하세요. 리액트 테스트 관련 좋은 강의를 제공해주셔서 감사합니다.수업 듣고 테스트 코드를 작성 시에 console.error로 wrapped in act 오류가 표시되어 문의드리게 되었습니다.여러 질문들도 찾아보고... 구글링도 해보며 방안을 찾아서 테스트코드가 성공하는 것 까지는 봤으나, 로그에 첨부드리는 이미지와 같이 표시되어지고 있습니다... useEffect에서 state변경시에 발생되는 것 같은데.. 이부분은 어떻게 처리해야할가요..?ㅠ 며칠을 찾아보고.. 제공해주신 소스코드도 확인해봤지만... 다른 부분이 없어 문의드립니다.(추가로.. 첨부 주신 코드의 리액트버전을 제가 구성하는 버전으로 구성 후 테스트 진행 시에 저와 동일한 결과가 나오는 것을 확인했습니다.)감사합니다.
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
todoData.map 화살표 함수 질문
[JSX Key 속성 이해하기] 파트에서는 todoData에 map 메서드를 사용할 때 this.todoData.map((value) => ( <div style={this.getStsyle()} key={value.id}> <input type="checkbox" defaultChecked={false} /> {value.title} <button style={this.btnStyle}>X</button> </div> ))로 return 없이 사용하셨는데 전 기존에는 this.todoData.map((value) => { return ( <div style={this.getStsyle()} key={value.id}> <input type="checkbox" defaultChecked={false} /> {value.title} <button style={this.btnStyle}>X</button> </div> ) })이렇게 사용했습니다 둘다 정상 동작하는데 차이점이 뭔지 궁금합니다
-
미해결Practical Testing: 실용적인 테스트 가이드
생성자 검증
안녕하세요 우빈님!빌더 패턴 사용 시 생성자 검증을 어떻게 하는 것이 좋을까에 대한 질문을 드리고 싶습니다..!변경 가능성이 있는 도메인 검증을 진행 할 때 빌더 패턴이 적용 된 private 생성자에서 검증을 진행하나요?저 또한 정적 팩토리 메서드를 즐겨썼었는데 Builder를 사용하고나니 어느 위치에서 검증을 하는게 좋을까에 대한 의문이 생기더라구요.기본적으로는 보통 정적 팩토리 메서드에서 생성자 검증을 진행하게 되면 도메인에서 검증을 위한 private 메서드가 전부 static이 되어야하는데 이게 옳은가? 라는 의문이 들기도 하고그렇다고 private한 빌더 쪽에 생성자 검증을 하려고 하니 외부 세계에 영향을 받는 가령 클라이언트로 부터 입력받은 시간이 현재 시간 이전 일 수 없습니다. 라는 테스트를 수행해야 할 때 외부로부터 계속해서 LocalDateTime.now() 를 전파받아서 구현을 해야하는데 이 필드를 생성자에 추가하는 것도 아닌 것 같고..이러한 고민 속에서 결국 생성자에서 진행됐어야 할 검증을 서비스 로직에서 도메인의 검증 메서드를 따로 호출하였는데 서비스 로직에서 검증 메서드를 호출하는 것 또한 좋은 방법은 아닌 것 같다는 생각이 들었습니다.이러한 상황에서 우빈님은 보통 어떤 방식을 택하시는지 궁금합니다 ㅎㅎ
-
미해결스프링부트 JUnit 테스트 - 시큐리티를 활용한 Bank 애플리케이션
로그아웃 질문입니다.
안녕하세요 강사님.현재 강의를 듣고 로그인과 회원가입은 서버에 구축하는 것으로 이해하였습니다.혹시 로그아웃의 경우에는 어떻게 처리를 해줘야 하는건지 궁금합니다. 현재 강의에서 쓴 코드를 백엔드로 쓰고, 프론트엔드는 리액트를 한번 사용해서 로그인했을떄 반환하는 토큰을 저장하려고 하는데 로그아웃 버튼을 눌렀을 떄는 어떻게 처리해야하는지 궁금합니다...! 로컬스토리지에서 토큰을 지우는 작업만 하는지, 아니면 서버에서 처리해줘야 하는지와 구현 방식도 혹시 가르쳐주실수 있으면 조언 주시면 너무나 감사하겠습니다.. 좋은하루되세요!!!
-
미해결Java/Spring 주니어 개발자를 위한 오답노트
안녕하세요 아랫분 질문에 서 궁금한점이 있어서 질문드립니다
교정하면 Service Class에서 Repository를 이용해서 Member를 가져옵니다. Repository는 MemberEntity를 Member로 변환한 도메인 모델을 반환해야 합니다. 서비스는 MemberEntity를 알지 못해야 합니다. 이렇게 말씀해주셨는데 1 .이렇게 분리하는 이유는 서로의 결합을 낮추기 위해서인가요? 이렇게 분리를하면 어쩔수없이 서비스 메서드 안에도메인클래스로 변환하는 로직이들어가 오히려 코드가 길어져서가독성을 해치지는않나요?현재 저는 서비스에서 레파지토리에서 엔티티를 가져온후dto 객체로 변환시켜서 (바로 변환을 시키거나 어셈블리라는 클래스를 만들어 여기서 변환 작업을 따로해주는 객체를 만들거나)컨트롤러로 넘겨줍니다. 보편적으로 이방식을 많이했는대따로 도메인 클래스를 생성해서 변환해서 비즈니스로직을 처리하고 dto 객체로 넘겨서 컨트롤러로 전달하는지 왜? 이런건지좀더 자세히 설명해주시면감사하겟습니다 ( 제가 수업을 좀더 열심히듣지않아 질문이 무례한게있음 용서해주세요 ㅠ ㅠ)
-
해결됨Practical Testing: 실용적인 테스트 가이드
null 검증
안녕하세요! 우빈님. 테스트 강의에서 많은 인사이트를 얻고 갑니다! 작은 고민이 하나 있는데요! 우빈님은 어떻게 생각하시는지 궁금하여 여쭈어봅니다!바로 도메인 객체에서의 null 검증인데요!BeanValidation을 통해서 Presentation에서 검증을 하더라도, 도메인 단에서 또 null 검증을 해주어야 하는가에 대한 질문입니다. 팀원들과 팀플을 하다보면 @NotNull 을 이용하여 Presentation 단에서 검증이 될텐데, 도메인에서도 null 검증을 해주어야 하는가!? 에 대한 질문을 많이 받습니다. 개인적으로 저는 Presentation 단에서 검증이 되더라도 실제로 객체가 생성될 때 까지의 일련의 과정들 속에서 객체에 온전한 값이 들어가지 않을 것 같아 null 체크 또한 해주는 것이 안정적인 코드를 만들어 줄 수 있다고 생각하는 편인데요! 이러한 작업들이 그래도 비용이 들어가는 측면이라, 개발 속도에 영향을 미쳐서 그런지 선호하지 않는 분들도 종종 만났던 것 같습니다! 혹시 우빈님 생각은 어떤지 의견을 한 번 여쭈어보고 싶습니다
-
미해결Practical Testing: 실용적인 테스트 가이드
현재 시간에 의존하는 코드
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요. 테스트 강의를 보고 실천(?)하고 있는 개발자입니다!최근 현재 시간에 대한 테스트를 짜던 도중, 현재 시간을 모킹하는 방법이 있다는 걸 알게 됐습니다. 우빈님 강의에서는 현재시간을 파라미터로 받는 방식을 통해 테스트를 짜셨는데, 두 가지 방법에 대해 어떻게 생각하시는지 의견이 궁금합니다!
-
미해결Practical Testing: 실용적인 테스트 가이드
OrderRepositoryTest에서 발생한 에러
package sample.cafekiosk.spring.domain.order; @ActiveProfiles("test") @DataJpaTest class OrderRepositoryTest { @Autowired private OrderRepository orderRepository; @Autowired private ProductRepository productRepository; @DisplayName("특정 주문 상태에 따라 주문을 조회한다") @Test void findOrdersBy() { //given Product product1 = createProduct("아메리카노", 3000, HANDMADE, SELLING); Product product2 = createProduct("카페라떼", 4000, HANDMADE, SELLING); Product product3 = createProduct("카푸치노", 5000, HANDMADE, SELLING); List<Product> products = List.of(product1, product2, product3); LocalDateTime startTime = LocalDateTime.of(2023, 10, 19, 0, 0); LocalDateTime orderTime = LocalDateTime.of(2023, 10, 19, 10, 0); LocalDateTime endTime = LocalDateTime.of(2023, 10, 20, 0, 0); Order completedOrder = createOrder(orderTime, PAYMENT_COMPLETED, products); Order canceledOrder = createOrder(orderTime, CANCELED, products); // when List<Order> orders = orderRepository.findOrdersBy(startTime, endTime, PAYMENT_COMPLETED); // then assertThat(orders).hasSize(1) .extracting("id", "orderStatus", "totalPrice", "registeredDateTime") .containsExactlyInAnyOrder( tuple(1L, PAYMENT_COMPLETED, 12000, orderTime) ); } private Product createProduct(String name, int price, ProductType productType, ProductSellingStatus productSellingStatus) { Product product = Product.builder() .name(name) .price(price) .type(productType) .sellingStatus(productSellingStatus) .build(); return productRepository.save(product); } private Order createOrder(LocalDateTime now, OrderStatus orderStatus, List<Product> products) { Order order = Order.builder() .products(products) .orderStatus(orderStatus) .registeredDateTime(now) .build(); return orderRepository.save(order); } @DisplayName("찾고자 하는 시간 안에 있는 주문을 조회한다") @Test void findOrdersBy2() { //given Product product1 = createProduct("아메리카노", 3000, HANDMADE, SELLING); Product product2 = createProduct("카페라떼", 4000, HANDMADE, SELLING); Product product3 = createProduct("카푸치노", 5000, HANDMADE, SELLING); List<Product> products = List.of(product1, product2, product3); LocalDateTime startTime = LocalDateTime.of(2023, 10, 19, 0, 0); LocalDateTime orderTime = LocalDateTime.of(2023, 10, 19, 10, 0); LocalDateTime endTime = LocalDateTime.of(2023, 10, 20, 0, 0); LocalDateTime overTime = LocalDateTime.of(2023, 10, 20, 10, 0); Order completedOrder = createOrder(orderTime, PAYMENT_COMPLETED, products); Order overTimeOrder = createOrder(overTime, PAYMENT_COMPLETED, products); // when List<Order> orders = orderRepository.findOrdersBy(startTime, endTime, PAYMENT_COMPLETED); // then assertThat(orders).hasSize(1) .extracting("id", "orderStatus", "totalPrice", "registeredDateTime") .containsExactlyInAnyOrder( tuple(1L, PAYMENT_COMPLETED, 12000, orderTime) ); } }각각 Test 수행할 땐 정상적으로 잘 동작했습니다. 하지만, 같이 Test을 수행하는 경우 findOrdersBy()에서 아래와 같은 에러가 발생하고 있습니다2023-10-20 23:12:40.519 INFO 8704 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@1a6c1270 testClass = OrderRepositoryTest, testInstance = sample.cafekiosk.spring.domain.order.OrderRepositoryTest@2d114d27, testMethod = findOrdersBy@OrderRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@18a136ac testClass = OrderRepositoryTest, locations = '{}', classes = '{class sample.cafekiosk.spring.CafeKioskApplication}', contextInitializerClasses = '[]', activeProfiles = '{test}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@560348e6, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@6f1c29b7, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@fb58afcf, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@7b7fdc8, [ImportsContextCustomizer@77d67cf3 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, eJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@27d5a580, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@40d10264]; rollback [true] Hibernate: insert into product (id, created_date_time, modified_date_time, name, price, product_number, selling_status, type) values (default, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into product (id, created_date_time, modified_date_time, name, price, product_number, selling_status, type) values (default, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into product (id, created_date_time, modified_date_time, name, price, product_number, selling_status, type) values (default, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into orders (id, created_date_time, modified_date_time, order_status, registered_date_time, total_price) values (default, ?, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into orders (id, created_date_time, modified_date_time, order_status, registered_date_time, total_price) values (default, ?, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: insert into order_product (id, created_date_time, modified_date_time, order_id, product_id) values (default, ?, ?, ?, ?) Hibernate: select order0_.id as id1_2_, order0_.created_date_time as created_2_2_, order0_.modified_date_time as modified3_2_, order0_.order_status as order_st4_2_, order0_.registered_date_time as register5_2_, order0_.total_price as total_pr6_2_ from orders order0_ where order0_.registered_date_time>=? and order0_.registered_date_time<? and order0_.order_status=? 2023-10-20 23:12:40.621 INFO 8704 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@1a6c1270 testClass = OrderRepositoryTest, testInstance = sample.cafekiosk.spring.domain.order.OrderRepositoryTest@2d114d27, testMethod = findOrdersBy@OrderRepositoryTest, testException = java.lang.AssertionError: [Extracted: id, orderStatus, totalPrice, registeredDateTime] Expecting actual: [(3L, PAYMENT_COMPLETED, 12000, 2023-10-19T10:00 (java.time.LocalDateTime))] to contain exactly in any order: [(1L, PAYMENT_COMPLETED, 12000, 2023-10-19T10:00 (java.time.LocalDateTime))] elements not found: [(1L, PAYMENT_COMPLETED, 12000, 2023-10-19T10:00 (java.time.LocalDateTime))] and elements not expected: [(3L, PAYMENT_COMPLETED, 12000, 2023-10-19T10:00 (java.time.LocalDateTime))] , mergedContextConfiguration = [MergedContextConfiguration@18a136ac testClass = OrderRepositoryTest, locations = '{}', classes = '{class sample.cafekiosk.spring.CafeKioskApplication}', contextInitializerClasses = '[]', activeProfiles = '{test}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper=true}', contextCustomizers = 왜 id가 3인가요?? 저는 DataJpaTest을 수행하면 각각의 Test 마다 rollBack이 수행되어 id가 당연히 1이라고 생각했었습니다. 왜 3이 되는지 이해가 되지 않습니다
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
SystemUuidHolder를 테스트하는 경우
Interface를 이용하여 완충재를 두고 테스트를 할 때는 테스트를 위한 mock 구현체를 이용하여 final 메소드를 stub하는 것을 피한다는 것은 이해를 했는데요. 갑자기 드는 생각이 결국 프로젝트가 배포될 때는 SystemUuidHolder라는 구현체를 사용하게 되고 그러면 해당 클래스의 대한 테스트도 진행해야 하나요? 진행한다면 해당 클래스는 UUID를 사용하고 있으니 final 메소드를 stub하는 상황을 피할 수 없게 되는건가요?
-
미해결Practical Testing: 실용적인 테스트 가이드
정적 팩터리 메서드 사용 기준?
제목 그대로 언제 사용하시는지에 대해 얘기를 나눠보고 싶어 질문 남깁니다.제 경우는 영속성 계층에 새로운 객체가 추가될 때 (RDB에 레코드를 추가할 때) new 키워드를 사용하여 id 값을 생성자로 받지 않는 생성자를 열어두고,존재하는 도메인 엔티티 혹은 영속성 엔티티를 영속성 계층으로부터 불러올 때는 정적 팩터리 메서드를 사용하는데강의를 진행하시면서 습관적으로 생성자 대신 static 메서드를 통해 생성 하시더라구요, 강사님만의 명확한 기준이 있으신지 궁금합니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
ProductRepository에 @Repository 어노테이션을 붙인 이유
스프링 컨테이너가 뜰 때 Jpa의 Repository 인터페이스 하위 타입을 스캔하여 빈으로 등록하는 것으로 알고 있어서 ProductRepository가 자동으로 스캔이 될텐데 @Repository 어노테이션을 붙이신 이유가 궁금합니다