묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Practical Testing: 실용적인 테스트 가이드
동시성 테스트와 데이터 초기화
안녕하세요 선생님 배운 테스트 강의를 통해 사이드 프로젝트를 하며 성장 중입니다.동시성 테스트를 하던 중 문제가 발생 하였고 해결은 하였으나 다른 방법이 있는지 조언을 구하고자질문을 남기게 되었습니다. 먼저 엔티티에 대한 설명을 드리겠습니다.모임과 모임 참여 테이블이 1 : N모임 참여 회원 테이블이 N : 1 입니다.모임은 최대 인원인 capacity를 가지고 있습니다.여러 회원이 모임에 동시 참여 했을때 인원수를 제한 되는지 보기 위한 테스트 입니다.동시성 문제를 막기 위해 비관적락을 모임을 조회 할때 사용 하였습니다. DB는 MYSQL을 사용 하였습니다.트랜잭션의 격리 수준은 기본인 REPEATABLE READ 을 사용 하였습니다.테스트 트랜잭션에서 모임을 저장 하고 비동기 작업의 다른 스레드에서 모임 조회를 시도 할 경우테스트의 모임 저장은 커밋되지 않은 트랜잭션으로 조회가 불가능한 문제가 있었습니다.문제 해결 방안으로는테스트 트랜잭션 어노테이션 제거비동기 작업 스레드를 통한 트랜잭션 커밋으로 이후 트랜잭션이 모임을 조회 하는 방법테스트의 일관성을 위해 2번 방법을 선택 하였습니다.모임과 회원을 저장하는 부분을 비동기 작업 스레드를 통해 커밋 하고이후 스레드의 트랜잭션으로 조회 하여 데이터를 읽을수 있도록 하였습니다. 테스트는 정상적으로 통과 되었지만 문제가 발생 했습니다.스레드 작업의 트랜잭션 커밋으로 다른 테스트에 영향이 가는 문제 입니다. 원인은 테스트 트랜잭션이 전파 되지 않음에 따라 스레드 작업이 롤백 되지 않았습니다.@Test void not_executors_Tx() { log.info("외부 트랜잭션 시작"); TransactionStatus outer = txManager.getTransaction (new DefaultTransactionAttribute()); log.info("outer.isNewTransaction={}", outer.isNewTransaction()); log.info("내부 트랜잭션 시작"); TransactionStatus inner = txManager.getTransaction (new DefaultTransactionAttribute()); log.info("inner.isNewTransaction={}", inner.isNewTransaction()); } 결과 : outer.isNewTransaction = true / inner.isNewTransaction = true @Test void executors_Tx() { //given log.info("외부 트랜 잭션 시작"); ExecutorService executorService = Executors.newFixedThreadPool(5); TransactionStatus outer = txManager.getTransaction (new DefaultTransactionAttribute()); log.info("outer.isNewTransaction() = {}", outer.isNewTransaction()); log.info("내부 트랜 잭션 시작"); executorService.submit(() -> { TransactionStatus inner = txManager.getTransaction (new DefaultTransactionAttribute()); log.info("inner.isNewTransaction() = {}", inner.isNewTransaction()); }); executorService.shutdown(); } 결과 : outer.isNewTransaction = true / inner.isNewTransaction = false 커밋한 스레드의 결과로 인해 전체 테스트에 영향이 가게 되었습니다.밑의 페이징 정보 조회 테스트를 실행 하기 전에 모임 전체 조회를 해보니 테스터 라는스레드 작업에서 저장한 모임이 조회 되었습니다. 어떻게 하면 커밋된 데이터들이 다른 테스트에 영향을 주지 않을까?를 고민 하였고생각한 해결 방안은 @AfterEach를 사용 하자 였습니다.하지만 해결 되지 않았습니다. 다른 테스트 에선 여전히 커밋된 테스터 모임이 발견 되었습니다.이 부분은 왜 delete가 되지 않았는지 모르겠습니다.추측 하기로는 REPEATABLE READ 격리 수준에서 자신이 트랜잭션을 시작 하였을때 데이터만조회 하고 삭제 할수 있기 때문에 테스트 트랜잭션 에서는 스레드가 추가한데이터를 조회, 삭제가 불가능 해서 발생한 문제 이지 않을까 하는 추측 입니다. 그레서 모든 테스트에 @BeforeEach를 사용 하여 테스트 시작전에데이터를 모두 지우고 테스트 하니 통과 하였습니다. 선생님께 드리고 싶은 질문은 이렇게 해결 한것이 최선인지 궁금합니다.멀티 스레드는 테스트 할때 어떻게 동작 할지 모르기 때문에트랜잭션 어노테이션을 제거 하는 방법이 더 나을까요? @AfterEach void cleanUp() { userEventRepository.deleteAllInBatch(); bookmarkRepository.deleteAllInBatch(); eventRepository.deleteAllInBatch(); userRepository.deleteAllInBatch(); } @DisplayName("페이징 정보를 받아 모임을 조회 합니다.") @Test void getPagingEvents() { //given for (int i = 0; i < 10; i++) { Event event = createEvent("테스터" + i, "자전거 모임"); eventRepository.save(event); } Pageable pageable = PageRequest.of(1, 3); //when Slice<EventPreviewResponseDto> slice = eventService.getPagingEvents(pageable); //then assertThat(slice.getContent()) .extracting("author") .containsExactlyInAnyOrder("테스터3", "테스터4", "테스터5"); } @DisplayName("5명의 회원이 동시에 최대 인원이 3명인 모임에 참가 할때 3명만 참여 할 수 있다.") @Test void joinEventWhenParticipateAtTheSameTimeWithConcurrency() throws Exception { //given int taskCount = 5; ExecutorService executorService = Executors.newFixedThreadPool(5); CountDownLatch countDownLatch = new CountDownLatch(taskCount); Event findEvent = executorService.submit(() -> eventRepository.save(createEvent("테스터", "테스트 모임", 3))).get(); List<User> users = executorService.submit(() -> Stream .generate(() -> { User user = createUser("테스터", "testEmail"); userRepository.save(user); return user; }) .limit(taskCount) .toList()).get(); //when AtomicInteger exceptionCount = new AtomicInteger(0); for (User user : users) { executorService.submit(() -> { try { eventService.joinEvent(findEvent.getId(), user.getId()); eventRepository.flush(); // 엔티티 상태를 DB에 강제로 반영 } catch (BusinessException ex) { exceptionCount.incrementAndGet(); } finally { countDownLatch.countDown(); // 카운트다운 } }); } countDownLatch.await(); Long participateCount = executorService.submit( () -> userEventRepository.countParticipantByEventId(findEvent.getId())).get(); executorService.shutdown(); //then assertThat(participateCount).isEqualTo(3); assertThat(exceptionCount.get()).isEqualTo(2); }
-
미해결Practical Testing: 실용적인 테스트 가이드
동시성 문제 테스트 관련해서 질문드립니다.
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요. 개인 프로젝트를 진행하다 궁금한 점이 있어 질문드립니다.현재, 서로 다른 두 트랜잭션이 동시에 실행될 때 발생할 수 있는 동시성 문제를 해결하기 위해 락을 적용해두었습니다. 테스트 코드에서는 락이 없는 경우에는 문제 상황이 발생하고, 락 적용 시에는 정상 작동함을 보여주고자 합니다.인터넷에서 관련 자료를 찾아본 결과, Executor와 CountDownLatch를 활용하여 동시성 문제를 테스트하는 방식을 많이 사용하길래, 저도 이를 적용해 테스트를 구성하려 하고 있습니다. 멀티스레딩 환경에서는 실행 순서가 보장되지 않으므로, 운이 나쁘면 두 트랜잭션이 순차적으로 실행될 수도 있다고 생각했고 실행 순서를 제어하여 문제가 발생할 수 있는 상황을 코드로 만들어야 한다고 생각했습니다.그러나 Executor와 CountDownLatch만으로는 트랜잭션 단위로 묶인 작업들의 실행 순서를 제어하기 어려워, 원하는 동시성 문제 시나리오를 재현하는 데 한계가 있었습니다. wait, notify 등의 스레드 제어 메서드를 활용하면 원하는 실행 순서를 만들 수 있을 것 같지만, 이것이 최선의 방법인지 고민이 되어 질문드립니다. 선생님께서는 동시성 문제 테스트를 진행할 때, 실행 순서를 제어하여 문제가 발생하는 시나리오를 인위적으로 만들고 이런 상황에서도 정상 작동함을 확인하시나요? 아니라면 동시성 문제를 테스트할 때 어떤 방법을 사용하시는지 궁금합니다
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
react19에서는 react-beautiful-dnd가 설치되지 않습니다.
https://github.com/atlassian/react-beautiful-dnd/issues/2672react-beautiful-dnd is now deprecated #2672 Drag and Drop 기능 구현을 위한 다른 방법 설명이 필요합니다.
-
미해결자동차 개발 프로세스 (ASPICE)
A-SPICE라는 것은...?
안녕하세요. 항상 좋은 강의 감사합니다. A-SPICE라는 것이OEM입장에서는 TIER사들에게 단순히 "CLx 를 지켜라" 라고 요구사항에 명시하는 것이고 그것을 실제로 수행하는 주체는 tier1이나 tier2 같은 업체인건가요?? 아니면 OEM도 A-SPICE의 프로세스를 지키면서 업무를 하고 심사도 받고 그렇게 하는것인가요? 감사합니다.
-
해결됨Practical Testing: 실용적인 테스트 가이드
Mockito로 Stubbing하기 8분경 OrderRepository 테스트
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요 강의를 보다가 OrderRepository에 대한 테스트는 직접 짜보라는 말씀을 듣고 직접 한번 작성을 해봤습니다. @ActiveProfiles("test") @DataJpaTest class OrderRepositoryTest { @Autowired private OrderRepository orderRepository; @Autowired private ProductRepository productRepository; @DisplayName("원하는 주문 상태를 가진 주문들을 조회한다.") @Test void findOrdersBy() { // given Product product1 = createProduct("001", HANDMADE, SELLING, "아메리카노", 4000); Product product2 = createProduct("002", HANDMADE, HOLD, "카페라떼", 4500); Product product3 = createProduct("003", HANDMADE, STOP_SELLING, "팥빙수", 7000); productRepository.saveAll(List.of(product1, product2, product3)); Order order1 = createOrderWithOrderStatus(List.of(product1, product2), LocalDateTime.now(), PAYMENT_COMPLETED); Order order2 = createOrderWithOrderStatus(List.of(product3), LocalDateTime.now().minusDays(1), PAYMENT_COMPLETED); Order order3 = createOrderWithOrderStatus(List.of(product1, product2, product3), LocalDateTime.now().plusDays(1), PAYMENT_COMPLETED); orderRepository.saveAll(List.of(order1, order2, order3)); // when List<Order> orders = orderRepository.findOrdersBy( LocalDateTime.now().minusDays(1), LocalDateTime.now().plusDays(1), PAYMENT_COMPLETED ); // then assertThat(orders).hasSize(2) .extracting("orderStatus", "totalPrice", "registeredDateTime") .containsExactlyInAnyOrder( tuple(PAYMENT_COMPLETED, 8500, order1.getRegisteredDateTime()), tuple(PAYMENT_COMPLETED, 15500, order3.getRegisteredDateTime()) ); } private Order createOrder(List<Product> products, LocalDateTime registeredDateTime) { return Order.create(products, registeredDateTime); } private Order createOrderWithOrderStatus(List<Product> products, LocalDateTime registeredDateTime, OrderStatus status) { Order order = createOrder(products, registeredDateTime); order.updateOrderStatus(status); return order; } private Product createProduct(String productNumber, ProductType productType, ProductSellingStatus sellingStatus, String name, int price) { return Product.builder() .productNumber(productNumber) .type(productType) .sellingStatus(sellingStatus) .name(name) .price(price) .build(); } }이런 식으로 작성을 하였는데 제가 궁금한 점은createProduct는 대부분의 테스트 클래스에서 사용되는데 하나의 static 클래스와 같이 외부로 분리하는게 좋지 않을까 라는 생각을 해봤습니다. 저는 Order 클래스의 상태 변경을 위해서 updateOrderStatus라는 메소드를 생성 하였는데 (아직 해당 강의를 끝까지는 보지 않고 강의를 보기전에 먼저 테스트 코드를 작성 해보고 있습니다) 이런 식으로 테스트를 위해서 메소드를 생성 하는 경우도 괜찮을까요?제가 작성한 코드의 given 절이 너무 길어지는 느낌을 받았습니다. 현재는 order와 product를 생성 하는 정도이지만 더 복잡한 로직을 생성 할 경우 given이 너무 길어 지는것에 대한 해결 방안이 있을까요? 최대한 구글을 사용하여 찾아는 보았지만 우빈님의 생각도 궁금하여 여쭤보았습니다! 긴 글 읽어주셔서 감사합니다 🙂
-
미해결쥬쥬와 함께 하루만에 끝내는 스프링 테스트
S3통합 테스트 질문
통합 테스트 돌리는 중에java.lang.RuntimeException: java.net.URISyntaxException: Expected scheme-specific part at index 10: localhost:이런 에러가 나서 헤매고 있습니다 ㅜㅜ노션이랑 강의 다시 돌려보면서 틀린 부분 찾고 있는데 없는 것 같고요 scheme문제라고 해서 properties파일을aws.endpoint=localhost:4566 이거 에서aws.endpoint=http://localhost:4566 요걸로 바꿔도 에러가 발생하네요 어떻게 해결해야하나요?
-
미해결쉬운 모바일 테스트 자동화 시작하기 : Appium Studio
apk 및 ipa 파일 자동 인식 기능 문의 건
Appium Studio 화면에 좌측 중앙 Application 항목에서apk과 ipa 파일을 자동으로 인식해서 보여주는 것으로 생각되는데새로운 apk 또는 ipa 파일을 자동 인식 시키려면 어떤 폴더에 파일을 넣어야 하나요??그리고 확장자가 apk 또는 ipa 이면 자동 인식되는 건지 아니면 정의된 파일 형식이 있는 건지 문의 드립니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
테스트 환경 통합하기 질문 있습니다.
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 테스트 환경이 다르면 스프링을 새로 띄워야 된다고 하셨는데, 여기서 테스트 환경이란게 테스트 클래스마다 의존 관계를 주입 받는 클래스가 하나라도 달라지면 스프링이 새로 뜨게 되는 건가요??
-
미해결Practical Testing: 실용적인 테스트 가이드
하위 레이어가 상위 레이어를 알고 있는 경우에 대해 질문 있습니다.
안녕하세요. 하위 레이어가 상위 레이어를 알고 있는 경우는 좋지 않다고 하셨는데 만약에 도메인을 순수하게 유지하고 싶어서도메인 엔티티와 jpa 엔티티를 분리하고, service와 jpaRepository에 DIP를 적용하게 되면service에서는 repository 인터페이스를 사용하고,repository 인터페이스를 구현하는 repositoryImpl에서 jpaRepository를 사용하게 될 것 같습니다.이 경우에 repositoryImpl에서는 jpa 엔티티 -> 도메인 엔티티로 변환을 하고, 도메인 엔티티를 service로 반환해주어야 할 것 같은데이렇게 되면 하위 레이어인 infrastructure(persistance) 레이어에서 상위 레이어에 있는 도메인 엔티티에 대한 의존성이 생긴다고 생각하는데 이런 경우는 상위 레이어에 의존성이 생겨도 상관 없는 경우인가요??테스트 강의와 무관한 질문을 드려서 죄송합니다 ㅠㅠ
-
미해결Practical Testing: 실용적인 테스트 가이드
경계값 테스트 작성 시 질문 있습니다.
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요. 경계값을 테스트할 때는 하나의 테스트 메서드 안에 모두 작성하는게 맞는건가요?상품 등록시 상품 번호의 증가로 예를 들면한 자리 -> 한 자리 ( 1 -> 2 )한 자리 -> 두 자리 ( 9 -> 10 )두 자리 -> 세 자리 ( 99 -> 100 ) 이런 식으로 작성할 수 있을 것 같은데, 이렇게 경계값에 대한 모든 경우를 한 메서드에 작성하는게 맞는 것 같긴한데, 경계값이 많아지면 좀 알아보기 힘들 것 같아서 여쭤봅니다..
-
미해결Practical Testing: 실용적인 테스트 가이드
비지니스 로직이 퍼시스턴스 계층에 침투하는 경우 관련해서 질문드립니다.
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요 Business Layer 테스트 (1) 강의 시작 부분에서 Querydsl을 쓰거나 별도의 DAO를 사용하면서 비지니스 로직이 퍼시스턴스 계층에 침투하게 작성하는 경우가 있다고 하셨는데 좀 더 구체적인 예시를 들어주실 수 있나요?그리고 요구사항이 복잡하여 엔티티를 가져오는 쿼리 역시 복잡해지는 경우, 이는 비즈니스 로직이 침투한 것으로 봐야할까요? 일반적인 CRUD 쿼리와 달리 특정 쿼리만 복잡하다면 추가적인 요소가 반영되었을 수도 있다 생각했고 따라서 이러한 경우를 비즈니스 로직의 개입으로 판단해야 하나 의문이 들어 질문 드립니다.
-
미해결테스트 with Jest: 제로초에게 제대로 배우기
안녕하세요 jest toHaveBeenCalledTimes 관련 질문드립니다.
전체 코드는 다음과 같습니다.(오류내용) mock 관련 toHaveBeenCalledTimes 질문드릴려는데요. toHaveBeenCalledTimes가 처음에는 기대값이 1로 맞아서 에러가 안나는데요. 두번째 테스트부터 첫번쨰 테스트에서 호출된 obj.minus 함수가 호출이 읽혀서 그런지 toHaveBeenCalledTimes의 기대값이 2가 됩니다. 세번쨰 테스트도 위에서 호출된게 있어서 그런지 기댓값이 5가 되구요 네번째 테스트도 마찬가지입니다. 원래 toHaveBeenCalledTimes 함수가 다른 테스트케이스에서 사용된 함수도 읽히는지 궁금합니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
Spring Rest Docs request에 List 타입이 포함된 경우
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요. 강의 너무 잘 듣고 있습니다! 현재까지 진행해온 프로젝트의 OrderController에도 Spring Rest Docs를 적용해보는 와중에 몇가지 질문이 생겼습니다!public class OrderControllerDocsTest extends RestDocsSupport { private final OrderService orderService = mock(OrderService.class); private static List<ProductResponse> productResponses; @Override protected Object initController() { return new OrderController(orderService); } @BeforeEach void init() throws Exception { ProductResponse productResponse1 = ProductResponse.builder() .id(1L) .price(1000) .sellingStatus(SELLING) .productNumber("001") .type(HANDMADE) .name("상품명1") .build(); ProductResponse productResponse2 = ProductResponse.builder() .id(2L) .price(3000) .sellingStatus(SELLING) .productNumber("002") .type(HANDMADE) .name("상품명2") .build(); productResponses = List.of(productResponse1, productResponse2); } @DisplayName("새로운 주문을 생성한다.") @Test void createOrder() throws Exception { //given LocalDateTime now = LocalDateTime.of(2025, 1, 28, 0, 50); List<String> productNumbers = List.of("001", "002"); OrderCreateRequest request = OrderCreateRequest.builder() .productNumbers(productNumbers) .build(); int totalPrice = productResponses.stream().mapToInt(ProductResponse::getPrice).sum(); OrderResponse orderResponse = OrderResponse.builder() .id(1L) .registeredDateTime(now) .products(productResponses) .totalPrice(totalPrice) .build(); given(orderService.createOrder(any(OrderCreateServiceRequest.class), any(LocalDateTime.class))) .willReturn(orderResponse); //when mockMvc.perform(post("/api/v1/orders/new") .content(mapper.writeValueAsString(request)) .contentType(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andDo(document("order-create", preprocessRequest(prettyPrint()), // adoc에서 json 형태를 보기 좋게 만들어줌 preprocessResponse(prettyPrint()), requestFields( fieldWithPath("productNumbers").type(JsonFieldType.ARRAY) .description("상품 리스트") ), responseFields( fieldWithPath("code").type(JsonFieldType.NUMBER) .description("코드"), fieldWithPath("status").type(JsonFieldType.STRING) .description("상태"), fieldWithPath("message").type(JsonFieldType.STRING) .description("메시지"), fieldWithPath("data").type(JsonFieldType.OBJECT) .description("응답 데이터"), fieldWithPath("data.id").type(JsonFieldType.NUMBER) .description("주문 ID"), fieldWithPath("data.totalPrice").type(JsonFieldType.NUMBER) .description("총 주문 가격"), fieldWithPath("data.registeredDateTime").type(JsonFieldType.ARRAY) // 반환타입 ARRAY ? .description("주문 시간"), fieldWithPath("data.products").type(JsonFieldType.ARRAY) .description("주문 상품 리스트"), fieldWithPath("data.products[].id").type(JsonFieldType.NUMBER) .description("주문 상품 ID"), fieldWithPath("data.products[].productNumber").type(JsonFieldType.STRING) .description("주문 상품 번호"), fieldWithPath("data.products[].type").type(JsonFieldType.STRING) .description("주문 상품 타입"), fieldWithPath("data.products[].sellingStatus").type(JsonFieldType.STRING) .description("주문 상품 상태"), fieldWithPath("data.products[].name").type(JsonFieldType.STRING) .description("주문 상품명"), fieldWithPath("data.products[].price").type(JsonFieldType.NUMBER) .description("주문 상품 가격") )) ); } }OrderService.createOrder() 메서드 반환 값 OrderResponse를 생성하기 위해선 ProductResponse 객체가 필요합니다. 이러한 경우가 강사님이 말씀하신 @BeforeEach의 적용시점인가? 라는 생각이 들어 위와 같이 작성해봤습니다. 제가 이해한 바가 맞을까요?? requestFields( fieldWithPath("productNumbers").type(JsonFieldType.ARRAY) .description("상품 리스트") ),위 코드에서 productNumbers에 있는 각 원소의 타입이 String 인것을 API 문서에 나타내고 싶어 fieldWithPath("productNumbers[]").type(JsonFieldType.STRING과 같이 작성해봤지만 타입 미스매칭 오류가 발생했습니다. responseFields에는 동일한 방법으로 List 순회에 성공했지만 requestFields 순회 문제는 해결하지 못했습니다.혹시 방법이 있다면 알려주시면 감사하겠습니다!
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
JPA가 아닌 Mapper 아키텍처 기반 테스트 코드 작성
안녕하세요, 수업 강의는 JPA 기반으로 설명해 주고 계신데 만약 Mapper 아키텍처 기반도 해당 강의 repository 테스트 코드 작성한 것 기반으로 적용하면 되나요?
-
해결됨SW 역량테스트 합격하기 A형 with C++ (Advanced Algorithm)
안녕하세요 선생님 코드트리 원자충돌(2020 하반기 오전 2번)에서 질문 있습니다.
안녕하세요 선생님원자 충돌(코드트리, 2020 하반기 오전 2번)에서 질문 있습니다.처음에 짤때 낚시왕(BOJ 17143)을 떠올리고 아래 처럼 코드를 짰는데 오답이 나옵니다.int dir=d; int dist = s%n; int sx = x; int sy = y; for(int cnt_k=0;cnt_k<dist;cnt_k++){ int nx = sx+dx[dir]; int ny = sy+dy[dir]; if(nx<0) nx=n-1; if(nx>=n) nx=0; if(ny<0) ny=n-1; if(ny>=n) ny=0; sx = nx; sy = ny; }이 부분만 선생님의 코드로 바꾸면 문제가 없어서 이 부분이 틀린 것이 확실한데 왜 오답인지 모르겠습니다 ..좋은 강의해주셔서 항상 감사드립니다 !.
-
미해결테스트 with Jest: 제로초에게 제대로 배우기
안녕하세요 제로초님
강의하신 내용에 대해 혹시 블로그에 정리해서 글을 작성해도 상관없을까요?
-
미해결Practical Testing: 실용적인 테스트 가이드
response의 위치에 대한 질문이 있습니다
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요현재 프로젝트에서는 service쪽에서 response로 변환을 해주고 있어서, response 객체의 위치가 service쪽에 있는데 response 변환을 controller 쪽에서 해주고 response의 위치도 controller쪽으로 옮기는 것에 대해서는 어떻게 생각하시나요?? service에서는 domain과 관련된 것들만 있는 게 좋지 않나? ( domain entity와 jpa entity를 구분하지 않고 있기는 하지만요.. ) 라는 생각이 있고, response는 api의 응답이라서 아무래도 controller쪽에 있는 게 좋을 것 같다고 생각을 해서 여쭤보게 됐습니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
repostory 테스트 코드 작성 이유 관련 질문
제가 테스트 코드 작성이 처음이라 잘 이해하지 못한 것 같은데요repository에서 테스트 코드를 작성하는 이유를 잘 모르겠습니다.. given에서 Product를 삽입하는 과정은 DB의 product에 레코드를 삽입하는 과정으로 대체해서 수행할 수 있을 것 같아서요. DB를 통해 확인하지 않고 리포지토리에 대해 테스트 코드를 작성하는 이유가 무엇일까요?혹시 수동 검증 시 콘솔에서 확인하는 것과 동일하게 직접 사람이 테스트 과정에 개입해야 해서 그러한 것일까요?
-
미해결Practical Testing: 실용적인 테스트 가이드
테스트 코드에서 data.sql 사용 없이 Product를 직접 생성한 이유
테스트 코드 작성 시에 data.sql을 활용하지 않으신 이유가 궁금합니다. @Test 메서드 내에서 Product를 생성하는 것보다 이미 작성된 data.sql을 활용하는 것이 더 편해보이는데 Product 인스턴스를 직접 생성하신 이유가 무엇인가요?혹시 테스트마다 필요로 하는 데이터가 다르기 때문인 것일까요?
-
미해결쥬쥬와 함께 하루만에 끝내는 스프링 테스트
성적 저장 어플 만들기 강의 관련 질문
강의 17분쯤에 save메서드를 postman에서 테스트를 해보았는데 Internal Server Error가 떠서 확인해보니cannot deserialize from Object value (no delegate- or property-based Creator) 에러가 뜨는 것을 확인할 수 있었습니다. 그래서 기존에@Getter @AllArgsConstructor public class SaveExamScoreRequest { private final String studentName; private final Integer korScore; private final Integer englishScore; private final Integer mathScore; }이렇게 써져있는 코드를@Getter @AllArgsConstructor @NoArgsConstructor public class SaveExamScoreRequest { private String studentName; private Integer korScore; private Integer englishScore; private Integer mathScore; }이렇게 바꾸니 정상적으로 응답을 반환함을 확인할 수 있었습니다.알아보니 해당 에러는 jackson생성자가 빈 생성자가 없는 객체를 만드는 법을 모르기 때문에 뱉는 에러라고 설명되어있어서 @NoArgsConstructor어노테이션을 추가하였고 final을 지워주었습니다.근데 강사님의 코드는 잘 돌아가는데 왜 제 코드는 저런 에러가 발생하는지 모르겠습니다. 혹시 스프링 버전하고도 관련이 있나요? (저는 현재 spring boot 3.4.1 버전을 사용하고 있기는 합니다.)