묻고 답해요
160만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
BDDMockito의 when을 사용한 코드가 given 절에 있는 이유가 궁금합니다.
섹션3 - 테스트추가하기: h2를 이용한 service 테스트 에서UserService의 create 를 테스트하기 위해 Mock으로 주입된 JavaMailSender의 send를 다음과 같이 given 절에 추가하셨습니다. https://tecoble.techcourse.co.kr/post/2020-09-29-compare-mockito-bddmockito/에 따르면 BDDMockito는 given-when-then 구조의 시나리오 기반 테스트를 진행할 때, 시나리오에 맞게 테스트가 읽힐 수 있도록 도와주는 역할이라고 하였습니다. 따라서 저는 해당 코드를 when 절에 추가하였는데, 다른 분들은 어떤 의견이신지 궁금합니다...!
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
테스트에서 주입과 생성
안녕하세요 좋은 강의 잘 듣고 있습니다. 사소한 질문이지만요..! <테스트 추가하기:mockmvc 를 이용한 controlelr 테스트 강의>의 13:00 에서요 ObjectMapper 를 @Autowired 로 주입받아서 쓰지 않고 생성하셔서 쓰는 이유가 있을까요? 각각은 어떻게 다르고 장단이 있나요. 미리 감사합니다.
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
프로젝트 코드는 제공해주시지 않는건가요?
안녕하세요? 강의 잘 듣고 있습니다강의보면서 코드를 따라치고 싶은데, 코드는 따로 제공되지 않는건가요?
-
미해결Practical Testing: 실용적인 테스트 가이드
MSA 환경에서의 Rest Docs 구성 환경 설정에 대한 문의
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요! 모든 강의 수강하였고, 강의 내용을 기반으로 기존 작업한 프로젝트에 리팩토링을 진행하고 있습니다.진행한 프로젝트는 MSA 기반으로, Swagger 를 사용하여 진행하였습니다.서비스가 나눠져 있어, 각 서버별로 독립적인 문서를 가지고 있고, 개발자가 각 서버에 접근을 해야하는 문제가 있었습니다.따라서 기존에는 Getway Server에 Swagger를 띄우고 각 서버를 discovery 서버에서 받아와서 api 호출을 통해 문서를 받아오게 하여 gateway에서 전체 문서를 열람 가능하게 하였습니다. 위와 같은 환경에서 동일하게, 단일 진입점으로 활용할 서버에 docs 설정을 통해 각 서버의 API 문서를 받아올 수 있게 구성하면 될까요? 아니면, 다른 방법이 있을까요? 현업에서 어떻게 구성하시는지 궁금합니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
테스트 코드 createOrderWithStock 로그에 관하여
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요 강사님. 테스트코드의 @Transactional은 마지막에 rollback을 하기 때문에 dirty checking을 하지 않고, 이로 인하여 update쿼리가 전송되지 않을것이라 생각했습니다.하지만 로그에는 update stock set created_date_time=?, modified_date_time=?, product_number=?, quantity=? where id=? Hibernate: update stock set created_date_time=?, modified_date_time=?, product_number=?, quantity=? where id=?이처럼 quantity를 변경한것에 대한 update쿼리가 전송되었습니다.이 부분에 대해서 찾아본 결과 "테스트 코드 마지막에서 stockRepository.findAll() 을 통해 stock을 전체 조회할때, select쿼리가 db에 직접 날라가기 때문에 select쿼리가 수행되기전 flush()로 인하여 update쿼리가 날아갔다." 라고 이해했습니다. 제가 이해한 내용이 맞을까요?
-
미해결내 마음대로 되지 않는 백엔드 테스트코드 - 희망편 & 현실편
테스트 데이터 관련 질문입니다.
게시글과 게시글 카테고리가 존재해야만 댓글을 작성할 수 있는 구조에서, 다음과 같은 시나리오를 테스트하고자 합니다.사용자가 댓글을 10개 작성하면 뱃지가 발급되는 시나리오를 테스트하려고 합니다.댓글을 작성하려면 게시글과 게시글 카테고리가 먼저 저장되어 있어야 하며, 댓글에는 post_id가, 게시글에는 post_category_id가 각각 존재합니다.이 상황에서 다음 질문이 있습니다: 댓글에 있는 post_id와 게시글에 있는 post_category_id를 nullable 하게 설정해도 괜찮을까요?
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
react 19의 useActionState가 더이상 isPending은 지원하지 않는 듯합니다
공식문서 내용입니다. 더이상 pending관련 값은 return해주지 않네요 공유차 전달드려요
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
개선된 아키텍처의 구조
많은 도움을 얻어가는 취준생입니다. 다름아니라 본 영상(레이어드 아키텍처의 문제점과 해결책) 9분30초의 구조는 DDD라고 볼 수 있나요?감사합니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
Spring REST Docs 관련 질문 사항
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요! 강의 유용하게 잘 보고 있습니다.테스트 기반 문서에 대해서 의문점이 있어 질문 드립니다. 기존에 작성한 MockMVC를 활용한 Controller단 테스트는, REST Docs를 사용하기 위해 만든 테스트가 있다면 중복되는 테스트는 제외를 해도 관계가 없을까요?예시로, 정상 Case 테스트와, 예외 Case (비교적 다수) 가 하나의 API에 테스팅 될 것 같은데, 정상 Case 테스트만 RestDocs로 운용, 나머지 예외 케이스는 Mocking 하여 별도의 Test 진행.아니면 controller 테스트는 Docs로 구분, 정상케이스만 .andDo(...) 적용하여 같은 테스트 파일에 포함되도록 설정 등등... REST Docs의 가장 큰 장점은 테스트가 완료된 API End Point만 명세화되어서 작성 된다고 느껴졌습니다. 테스트 코드를 통과해야 merge가 가능하도록 branch 전략을 수립하거나, CI/CD 과정에 포함시키는 등을 진행하면 Swagger를 통한 명세 작성에 비해 떨어지는 접근성을 지닐 수도 있다고 생각합니다.다만, 테스트코드의 강제성 부분에서는 장점이 있다고 생각되는데 혹시 다른부분의 장점이 또 있을까요?테스트 코드 작성 부분이 많이 약해 도움받을 목적으로 강의를 수강하게 되었는데, 많은 부분에서 도움을 받은 것 같습니다. 감사합니다!
-
미해결Practical Testing: 실용적인 테스트 가이드
실제 비즈니스에서 createOrder() 오버로딩에 관한 질문
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요! 강의를 듣는 중에 createOrder() 메소드에 관한 궁금한 점이 생겨 질문드립니다.좋은 예시와 설명으로 테스트를 어렵게 코드들을 외부로 빼서 테스트를 쉽게할 수 있게 하는 점을 잘 이해했습니다.그런데 강의에서 파라미터 주입으로 변경한 createOrder(LocalDateTime ) 메소드는 사실상 다른 비즈니스 클래스에서 사용한다고 했을 때 모두 LocalDateTime.now()을 파라미터로 사용할 것으로 생각됩니다.그래서 저렇게 파라미터로 뺀 경우 createOrder() 메소드를 사용하는 다른 비즈니스 클래스에선 불필요한 코드 반복이 발생할 수 있을 것 같고 또 개발자가 LocalDateTime.now() 대신 잘못된 값을 넣을 수 있게 되니 잠재적으로 예기치 못한 동작을 유도할 수도 있을 것 같다는 생각이 드는데 이런 부분들은 어떻게 생각하시는지 궁금합니다..!
-
해결됨Practical Testing: 실용적인 테스트 가이드
RestDocs snippets 경로 질문
bootJar.enabled = true jar.enabled = false configurations { asciidoctorExt } ext { snippetsDir = file('build/generated-snippets') } dependencies { implementation project(":core:core-domain") implementation project(":storage:db-main") implementation project(":support:logging") implementation project(":tests:api-docs") implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-websocket' implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'io.jsonwebtoken:jjwt-api:0.12.3' implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' } tasks.register('restDocsTest', Test) { group = 'verification' useJUnitPlatform { includeTags('restdocs') } } asciidoctor { inputs.dir snippetsDir configurations 'asciidoctorExt' sources { include ("**/index.adoc") } baseDirFollowsSourceFile() dependsOn restDocsTest }냅다 이미지 투척해서 죄송합니다.위의는 RestDocs Test가 포함된 하위 모듈의 그래들 입니다.멀티모듈이긴한데 경로는 강의랑 딱히 다를 거 없을 거 같아서했다가 상위로 5번이나 이동 시켜야 정상 작동하네요,,{docDir}이 src/docs/asciidoc 까지 잡혀가지고그런 거 같은데이거 설정은 어디서 할 수 있을까요,,
-
미해결스토리북 & 자동화 테스트와 함께 하는 컴포넌트 주도 프론트엔드 개발
질문을 올려주시면 답을 해드립니다.
강의자료와 발표에서 정말 많은 질문을 다루긴 했는데요. 궁금하신 점을 적어주시면 시간이 되는대로 답변을 해드리려 합니다~
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
서비스 레이어의 단위 테스트 범위 고민
테스트 중에 고민되는 부분이 생겨서 문의드립니다.A서비스의 a()메서드에서 B서비스의 b()메서드를 호출하고 있고, B서비스의 b()메서드에 대한 단위 테스트가 이미 완료된 상황을 예시로 들겠습니다. 이미 b()메서드에 대한 테스트는 끝났으니, A서비스 단위 테스트 시 a()가 b()를 호출해서 생기는 결과에 대해서는 따로 검증이 필요하지 않을까요? 저는 b()를 호출하는 것까지가 a()의 책임이기 때문에 a()를 테스트하려면 b() 호출에 따른 검증 과정도 필요하다고 생각됩니다.하지만 이 경우 여러개를 의존하는 클래스에 대한 테스트 시, assertThat()과 같은 검증 코드 및 테스트 코드가 뚱뚱해지는 일이 발생합니다.혹은 테스트 시 a()에서 B서비스의 b()를 호출했는 지에 대해 Mock라이브러리의 verified를 통해 검증 가능한 것으로 알고있는데, 모키토 같은 외부 라이브러리를 사용하지 않고 테스트를 작성하고 싶어 고민됩니다. 결국 A서비스를 단위 테스트할 때 어디까지 테스트하는 것이 적절한 책임 분배?인지 알고 싶습니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
테스트하기 어려운 영역 분리에서 질문이 있습니다.
public class GenerateUUIDAndTimestp { public static UUIDAndTimestpDto generateTidAndTimestp() { String uuid = UUID.randomUUID().toString(); // 하이픈 제거 String uuid2 = uuid.replace("-", ""); String epochTime = String.valueOf(System.currentTimeMillis() / 1000); return new UUIDAndTimestpDto(uuid2, epochTime); } } 안녕하세요. 학습 후 테스트를 적용해볼려고 하고 있는데요. 이런 식으로 UUID와 epochTime을 쉽게 사용할려고 유틸리티 클래스와 스태틱 메서드를 만들었습니다. 테스트를 위해 테스트 하기 어려운 부분을 분리하라고 하셨는데요. 해당 부분을 어떻게 테스트 해야할 지 모르겠습니다 ㅜㅜUUID야 인자로 뺄 수 있지만 System은 정적 클래스인데 인자로 빼기 어려운 부분과 쉽고 간편하게 사용할려고 만든 메서드인데 UUID나 System을 계속 인자로 넣어야 하나 하는 부분이 고민이 들게 만듭니다. 강의 잘 듣고 있습니다 감사합니다.
-
미해결실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
ProductFilter test 어떤 방식이 더 선호되는 방식일까요?
it('최소 가격 또는 최대 가격을 수정하면 setMinPrice과 setMaxPrice 액션이 호출된다.', async () => { const { user } = await render(<ProductFilter />); const minPriceInput = screen.getByPlaceholderText('최소 금액'); const maxPriceInput = screen.getByPlaceholderText('최대 금액'); await user.type(minPriceInput, '10'); await user.type(maxPriceInput, '10000'); expect(setMinPriceFn).toHaveBeenCalledWith('10'); expect(setMaxPriceFn).toHaveBeenCalledWith('10000'); }); 전 이런식으로 작성했습니다.단위 테스트에서 알려주신 AAA패턴을 해당 통합테스트에서도 적용하면 깔끔할 것 같아서 이렇게 작성했어요.어차피 검증할건 setMaxPriceFn & setMinPriceFn이 호출됐는지 여부라 최소금액 및 최대금액 인풋을 연속적으로 조작하게 했습니다.혹시 이렇게 하면 문제가 있는지 궁금합니다
-
해결됨2시간으로 끝내는 프론트엔드 테스트 기본기
테스트 자동화를 cypress cloud로 하는 이유
안녕하세요, 선생님. 강의를 모두 듣고 개인 프로젝트에 적용해보고 있는 중에 궁금한 점이 생겨 질문 남깁니다.이번 강의에 나온 cypress cloud를 사용해서 테스트 자동화를 해보았는데 문득 cypress가 아니라 cypress cloud를 사용해서 테스트 자동화를 하는 이유가 무엇인지 궁금하더라고요.https://docs.cypress.io/guides/continuous-integration/github-actions위 문서를 찾아보니 cypress cloud는 테스트를 병렬로 진행해서 속도가 더 빠르다고 하는데 병렬 테스트를 위해 cypress cloud를 사용하는 것인지 궁금합니다.아니면 뭔가 다른 이유가 있을까요?
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 2부. 테스트 심화: 시각적 회귀・E2E 테스트
unit-test-example 브랜치에서 'Test result not found.' 가 뜹니다...
unit-test-example에서 테스트를 실행하니 테스트코드 통과 여부에 관계없이 Test result not found만 뜨며 실패합니다. 이유를 모르겠어요ㅠㅠ Test result not found.If you set `vitest.commandLine` please check:Did you set `vitest.commandLine` to `run` mode? (This extension requires `watch` mode to get the results from Vitest api)Does it have the ability to append extra arguments? (For example it should be `yarn test --` rather than `yarn test`)Are there tests with the same name?Can you run vitest successfully on this file? Does it need custom option to run?
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
통합 테스트 작성 방식에 대해 궁금한 점이 있습니다
테스트는 내부 구현에 의존하지 않고 사용자 입장에서 작성하는게 좋다고 이해했습니다.그런데 ProductFilter 컴포넌트의 통합테스트를 작성하시면서 "상품명을 수정하는 경우 setTitle 액션이 호출된다", "최소 가격 또는 최대 가격을 수정하면 setMinPrice와 setMaxPrice 액션이 호출된다" 와 같이 사용자가 값을 변경할 때 특정 액션 함수가 호출되는지를 검증하셨는데, 이건 내부 구현에 의존적인 테스트라고 볼 수 없을까요?추후 Store 내부 구조가 바뀌거나 아예 Store를 사용하지 않는 식으로 구현 방법이 바뀌더라도 사용자 입장에선 달라지는게 없으니 테스트가 실패하지 않는게 좋은 테스트가 아닌지 궁금합니다.2. api를 호출하는 커스텀 훅을 사용하는 컴포넌트를 테스트하실 때 msw를 이용해 해당 api의 응답을 모킹하셨는데, 커스텀 훅 자체를 모킹해서 훅이 반환하는 값을 원하는대로 지정하는 것도 가능할 것 같습니다. 이렇게 api 대신 훅을 모킹하여 테스트하는 것에 대해 어떻게 생각하시는지 궁금합니다.
-
미해결리셀봇 원리로 알아보는 Cypress
Chrome 자동화된 테스트 소프트웨어에 의해 제어되고 있습니다
안녕하세요.혹시 cypress로 자동화 Bot을 만들려고 했는데 로그인 과정에서 Chrome 자동화된 테스트 소프트웨어에 의해 제어되고 있습니다 가 발생하여 문제가 발생하고 있습니다. 현재는 chromeWebSecurity: false,를 추가한 방법을 사용하였는데 다른 추가적인 방식이 필요한가요??
-
미해결Practical Testing: 실용적인 테스트 가이드
REST Docs 추가 작업중 직렬화,역직렬화 문제
강사님이 기존에 작성해주신 코드들을 가지고 REST Docs를 채워보려고 하고있습니다 !OrderController의 createOrder 메서드에 대해서 테스트 해서 docs를 채워보려고 하는 와중에 LocalDateTime에서 직렬화와 역직렬화 문제가 발생하여서 질문드립니다 ! public class OrderControllerDocsTest extends RestDocsSupport { private final OrderService orderService = mock(OrderService.class); @Override protected Object initController() { return new OrderController(orderService); } @BeforeEach void setUp() { objectMapper.registerModule(new JavaTimeModule()); objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); } @DisplayName("신규 주문을 생성하는 API") @Test void createOrder() throws Exception { OrderCreateRequest request = OrderCreateRequest.builder() .productNumbers(List.of("001", "002")) .build(); List<ProductResponse> productResponses = List.of( ProductResponse.builder() .id(1L) .productNumber("001") .type(HANDMADE) .sellingStatus(SELLING) .name("아메리카노") .price(4000) .build(), ProductResponse.builder() .id(2L) .productNumber("002") .type(HANDMADE) .sellingStatus(HOLD) .name("카페라떼") .price(4500) .build() ); given(orderService.createOrder(any(OrderCreateServiceRequest.class), any(LocalDateTime.class))) .willReturn(OrderResponse.builder() .id(1L) .totalPrice(8500) .registeredDateTime(LocalDateTime.now()) .products(productResponses) .build()); mockMvc.perform( post("/api/v1/orders/new") .content(objectMapper.writeValueAsString(request)) .contentType(MediaType.APPLICATION_JSON) ) .andDo(print()) .andExpect(status().isOk()) .andDo(document("order-create", preprocessRequest(prettyPrint()), 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.STRING) .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("상품 가격") ) )); } }이렇게 코드를 작성하니 LocalDateTime을 Array로 만들더라구요 일단 그래서 Array로 해서 반환하니까 물론 테스트는 문제없이 넘어가지만 실제 프로덕션 코드의 Response 코드를 확인해보니 LocalDateTime으로 String으로 넘어가고 있었습니다. 테스트와 실제 프로덕션 코드의 간극이 생기는데 어떻게 해결하면 좋을까요 ? 그리고 기존에 알려주셨던 ProductionControllerDocsTest의 코드를 많이 참고해서 테스트를 작성하였는습니다. 여기서 든 의문점이 이렇게만 작성하면 request와 response만 정의할 뿐 실제로 테스트는 동작하지 않는 것 아닌가 ? 라는 의문이 들었습니다. 실제로 OrderResponse.builder()를 맘대로 바꿔도 테스트가 깨지지않는 상황입니다. 그래서 단순히 Controller단 테스트는 수업때 설명하신 것 처럼 파라미터에 대한 검증만을 하는 것이기 때문에 REST Docs 또한 Request 와 Response의 필드가 어떻게 구성되어있는지 정도만 보여주는 용도로 사용되는건지도 궁금합니다 !