묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
테스트 코드에서 @BeforeEach가 아니라 sql 사용하시는 이유 문의드립니다.
안녕하세요!실무에서 테스트 코드 적용을 위해 강의를 열심히 듣고 있는 중 궁금한 부분이 있습니다. 테스트코드 사용 시 @BeforeEach를 사용하는 경우도 있는데, sql로 초기 데이터 추가를 사용하시는 이유가 궁금합니다. 작은 서비스가 아니고 복잡한 서비스의 경우 sql로 넣는게 편할것 같기는 한데, 상태에 따라 id값이 필요한 경우도 있고, sql로 작성 시 테스트 마다 데이터가 적용이 동일하지 않을 것 같기도 해서 실제 복잡한 프로젝트에서 어떻게 사용하시는지 궁금해서 문의드립니다.@BeforeEach가 한눈에 들어오지 않아서 잘 사용하지 않으신다고 설명해 주시기는 했지만, SQL로 사용 시 조회 등의 테스트에서는 특정 상태의 데이터 id를 알아야 하고, 그럼 SQL에서 해당 데이터의 id값과 상태값을 다시 확인해야 하는 형태는 동일하게 한눈에 안 들어올 것 같아서 고민이 되더라고요. 저도 SQL로 초기 데이터를 추가하는 형태로 사용하다가 이후에 테스트 코드의 유지보수가 쉽지 않은 경험이 있어서 강사님께서는 복잡한 비즈니스의 실무에서는 어떻게 사용하시는 궁금합니다. 감사합니다.
-
미해결따라하며 배우는 TDD 개발 [2023.11 업데이트]
TypeError: user_model_1.default.create is not a function
학습중 repository pattern을 적용하여 테스트를 적용해 보던 중 TypeError: user_model_1.default.create is not a function 라는 에러와 마주하게 되었습니다.user.repository.tsimport User from "../model/user.model"; export class UserRepository { createUser = async(user) => { const newUser = await User.create({ ...user }) return newUser } findUserById = async(id:string) => { const user = await User.findById('65cba34813b2fbec74a558a8') if(!user) throw new Error('존재하지 않는 유저정보 입니다.') return user } }user.repository.test.tsimport { UserRepository } from "../../app/repository/user.repository" const createMock = jest.fn() const findByIdMock = jest.fn() jest.mock("../../app/model/user.model", () => { return { User: jest.fn(() => { return { create:createMock, findById:findByIdMock } }) } }) describe('user repository Create', () => { let sut:UserRepository; const newUser = { id:"abcdefrwgsf123123", name:"test name", email:"test@nanana.com" } beforeEach(() => { sut = new UserRepository() }) afterEach(() => { jest.clearAllMocks() }) it('create api', async () => { createMock.mockReturnValueOnce(newUser) const actual = await sut.createUser({name:newUser.name, email:newUser.email}) expect(createMock).toHaveBeenCalledTimes(1) expect(actual).toStrictEqual(newUser) expect(createMock).toHaveBeenCalledWith({name:newUser.name, email:newUser.email}) }) }) jest실행시 create api의 createMock.mockReturnValue() 까지는 실행이되지만 await sut.createUser() 부분에서 에러가 나는것으로 확인되었습니다.
-
해결됨Practical Testing: 실용적인 테스트 가이드
혹시 @AllArgsConstructor 를 지양하시는 이유가 빌더 패턴을 사용하기 위함인가요?
private @Builder 를 통해서 객체 생성을 주로 하시는 이유가 Builder 패턴의 장점을 위해서 사용하시는 건지 궁금합니다!
-
해결됨Practical Testing: 실용적인 테스트 가이드
@RequestParam vs @ModelAttribute
강의에 나온 내용은 아니지만 개인적으로 개발을하다 궁금한 점이 생겨서 질문 드립니다.조회 API를 만들 때 (GET요청)Controller단에서 파라미터를 받는 방식이 @RequestParam, @ModelAttribute 크게 2가지 있는데 2가지 방식중 어떤 방식을 선호하지는지 질문드립니다. @RequestParm을 사용했을 때는 Controller단에서 바로 직관적으로 어떤 파라미터를 받는지 확인이 가능하다는 장점이 있지만 Service단으로 파라미터를 넘겨줄 때, 하나하나 넘겨줘야해서 파라미터가 추가되었을 때 불편하다는 점이 있을 테고@ModelAttribute를 사용했을 때는 수정에는 유리하겠지만 가독성은 떨어질 것 같다는 생각이 듭니다.강사님은 어떤 생각을 가지고 계신지, 현업에서는 주로 어떤방식으로 개발을 하는지 의견주시면 감사하겠습니다.
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
오류메세지는 확인했는데 어떻게 고쳐야 할지 모르겠습니다 ㅠ
TODO앱을 클래스앱에서 컴포넌트 함수형 으로 바꾸는과정에서 뭔가 문제가 생겼는지 아니면 이전부터 문제가 있었는지는 모르겠는데 이런오류가 뜨면서 되지않네요 ㅠㅠ 리액트 초짜라 뭘 어떻게 바꿔야할지 모르겠습니다 ㅠㅠ 답변부탁드립니다 감사합니다 ㅠㅠ위에 문제가 된다고 하는 6행 74행 사진입니다 ㅠㅠ
-
미해결Practical Testing: 실용적인 테스트 가이드
사용되는 아키텍처에 대해
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요 선생님 강의 잘보고 있습니다. 질문드리고 싶은 부분은 강의에서 사용되는 아키텍처에 대한 것입니다. 레이어드 아키텍처라는것은 이해했지만, 패키지 구조가 생소해서 어떻게 구성되는지는 이해하기 어려운것 같습니다. 제가 아는 방식은 컨트롤러, 서비스, 리파짓토리, 도메인 패키지로 단순하게 작성하는 방법인데, 여기서 사용된 패키지 구성방식과 관련된 키워드나 레퍼런스를 얻을 수 있을가요?
-
미해결따라하며 배우는 TDD 개발 [2023.11 업데이트]
에러 처리를 위한 단위테스트 작성
에러 처리를 위한 단위테스트 작성 강의 내용 중 이해가 가지 않는 부분이 생겨 글 남김니다.errorMessage 의 message 내용은 description property missing 에러입니다. 그렇다면 테스트 상황에서 포스트맨과 동일하게 description이 빠진 객체를 저장하다 에러가 발생해야 맞는 테스트가 아닌가 하는 의문이 생기네요.it('should handle errors', async () => {const errorMessage = {message: "description property missing"}; const rejectedPromise = Promise.reject(errorMessage); productModel.create.mockReturnValue(rejectedPromise); await controller.createProduct(req, res, next); expect(next).toBeCalledWith(errorMessage);})
-
해결됨Practical Testing: 실용적인 테스트 가이드
안녕하세요 재고 테이블에 대해서 질문 있습니다.!
안녕하세요 멘토님 강의 잘듣고 있습니다!제가 테이블을 언제 만들어야 하고 합쳐야 되는지에 대해서 잘 모르겠습니다. 혹시 검색 키워드와 상품테이블에서 재고를 관리하지 않고 따로 테이블을 만든 이유가 있을까요 ?
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
creactStore질문이요
미들웨어에서 rootReducer 하나만 넣었을 땐 문제 없는데 2번째 인자 넣을때부터 에러가 계속 나는데 이유를 모르겠습니다.
-
미해결Do It! 장고+부트스트랩: 파이썬 웹개발의 정석
맥북 프로 14 가상화 확인
안녕하세요 강사님 저는 지금 현재 도커 소개와 도커 설치 강의를 수강하고 있습니다. window에서는 작업 관리자에 들어가면 가상화를 확인할 수 있지만 제가 사용하고 있는 맥북 프로 14에서는 가상화가 사용되고 있는지 확인 할 수 없습니다. 그래서 구글에도 검색을 해 보았는데 무슨 말인지 정확히 이해하기 힘들어 질문을 남깁니다. 맥북 프로 14 모델에서는 가상화가 사용되고 있는것인가요? 만약 사용되고 있지 않다면 무엇을 어떻게 설치해야 하는지 알려주시면 감사하겠습니다.
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
혹시 git 플러그인 아시는 분
수업에서 git 커밋메세지 사용할 때 옆에 나오는 것들 어떻게 나오는지 아시는 분 계시나요?intellij 기능인지 플러그인인지 인 것 같은데요.아시는 분 있으시면 답변 주시면 감사하겠습니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
이상한 url로 요청해도 200이 반환됩니다. 그리고 body가 비어있어요...
@WebMvcTest(CompanyController::class) @ActiveProfiles("test") @WithMockUser class CompanyControllerTest { @Autowired lateinit var mockMvc: MockMvc @MockBean lateinit var getCompanyService: GetCompanyService @MockBean lateinit var adminAuthorizationFilter: AdminAuthorizationFilter private val cookie = Cookie(ADMIN_AUTH_TOKEN, "admin-auth-token") @DisplayName("회사 목록 조회") @Test fun findAll() { // given val companies = listOf( companyEntity(1, "A"), companyEntity(2, "B"), companyEntity(3, "C"), ) `when`(getCompanyService.findAll()).thenReturn(companies) // when val request = MockMvcRequestBuilders.get("/admin/api/v1/companies") .cookie(cookie).accept(MediaType.APPLICATION_JSON) // then mockMvc.perform(request) .andExpect(MockMvcResultMatchers.status().isOk) .andDo(MockMvcResultHandlers.print()) } } 위 코드를 가지고 질문드리겠습니다. val request = MockMvcRequestBuilders.get("/admin/api/v1/companies") 이 부분에서 companies가 아니라 존재하지 않는 url(ex. /admin/api/v1/cfasfsdfcompanies)라고 한 후 위 코드를 돌리면 200나옵니다. 존재하지 않는 url도 호출이 가능한건가요?그리고 body가 항상 빈 값입니다.MockHttpServletResponse: Status = 200 Error message = null Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"0", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"] Content type = null Body = Forwarded URL = null Redirected URL = null Cookies = []목킹이 잘못되었는지 점검해보려고 getCompanyService.findAll() 를 호출해보았는데 3개가 정상적으로 나옵니다. 혹시 몰라 소스 공유드립니다.// controller @RestController @RequestMapping("/admin/api/v1/companies") class CompanyController( private val getCompanyService: GetCompanyService ) { @GetMapping fun findAll(): List<CompanyResponse> { return getCompanyService.findAll().map { CompanyResponse.of(it) } } } // service @Service @Transactional(readOnly = true) class GetCompanyService( private val companyFindService: CompanyFindService ) { fun findAll(): List<CompanyEntity> { return companyFindService.findAll() } }
-
미해결Practical Testing: 실용적인 테스트 가이드
RestDocs에서의 SpringSecurity Issue
public class FollowControllerDocsTest extends RestDocsSupport { private FollowService followService = mock(FollowService.class); @Override protected Object initController() { return new FollowController(followService); } private final Long loginUserId = 1L; @DisplayName("팔로우 수행 API") @WithUserDetails @Test public void startFollow() throws Exception { // Given StartFollowRequestDto requestDto = StartFollowRequestDto.builder() .followerId(loginUserId) .followingId(123L) .build(); BDDMockito.doReturn(StartFollowResponseDto.success()) .when(followService) .follow(any(StartFollowRequestDto.class)); //when,then mockMvc.perform( post("/api/follow/start-follow") .with(csrf()) .content(objectMapper.writeValueAsString(requestDto)) .contentType(MediaType.APPLICATION_JSON) ) .andExpect(status().isOk()) .andDo(document("start-follow", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields( fieldWithPath("followerId").type(JsonFieldType.STRING) .optional() .description("팔로워 아이디"), fieldWithPath("followingId").type(JsonFieldType.STRING) .optional() .description("팔로잉 아이디") ), responseFields( fieldWithPath("code").type(JsonFieldType.STRING) .description(ResponseCode.SUCCESS), fieldWithPath("message").type(JsonFieldType.STRING) .description(SUCCESS) ) )); } } FollowController@RestController @RequestMapping("/api/follow") @RequiredArgsConstructor public class FollowController { private final FollowService followService; @PostMapping("/start-follow") ResponseEntity<? super StartFollowResponseDto> startFollow( @RequestBody @Valid StartFollowRequestDto requestBody, @AuthenticationPrincipal PrincipalDetails principalDetails ) { Long loginId = principalDetails.getUser().getId(); Long userId = requestBody.getFollowerId(); if (loginId != userId) return StartFollowResponseDto.certificationFail(); ResponseEntity<? super StartFollowResponseDto> response = followService.follow(requestBody); return response; } }RestDocsSupport @ExtendWith(RestDocumentationExtension.class) public abstract class RestDocsSupport { protected MockMvc mockMvc; protected ObjectMapper objectMapper = new ObjectMapper(); private final Long loginUserId = 1L; @BeforeEach void setUp(RestDocumentationContextProvider provider) { User user = mock(User.class); when(user.getId()).thenReturn(loginUserId); PrincipalDetails userDetails = mock(PrincipalDetails.class); when(userDetails.getUser()).thenReturn(user); SecurityContext context = SecurityContextHolder.getContext(); context.setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, null, null)); this.mockMvc = MockMvcBuilders .standaloneSetup(initController()) .apply(MockMvcRestDocumentation.documentationConfiguration(provider)) .build(); System.out.println("beforeEach 수행"); } protected abstract Object initController(); } 안녕하세요. 강의 정말 유익하게 잘 듣고있습니다. 강의를 듣고 restdocs를 작성하던 중 문제가 발생하여 질문을 올립니다.제가 작성한 controller에서는 파라미터로 security.context 안에 있는 PrincipalDetails를 받아옵니다. 그렇지만 테스트에선 그 안에 값이 있는게 아니여서 Mock값을 넣어주어 @WebMvcTest 에서는 문제를 해결해 왔었습니다.문제는 restdocs를 작성하기 위한 테스트 코드에서 발생하였습니다. 이 테스트 코드에는 제가 적용한 PrincipalDetails 몫 이 넣어지지 않는 문제가 있었습니다.제가 생각하기론 SpringSecurity가 올라가지 않아서 그런 것 같은데 해결방법이 있으면 알고싶습니다 !
-
해결됨Practical Testing: 실용적인 테스트 가이드
패키지 구조에 대해서 질문 드리고 싶습니다.
강의 너무 잘들었습니다 강사님 :)도움 너무 많이 되고있습니다“패키지 구조에 대한 질문이라는 글을 읽고서 product 패키지-domain 패키지-service 패키지-repository패키지아니면controller패키지-product패지지service패키지-product패키지어떤게 더 나을지 고민입니당 ㅠ 어떻게 생각하시나요?rest api 서버로 프로젝트를 처음 진행하려고 하는데 어떻게 나눌지를 잘 모르겠어서 검색 키워드나 실무에서는 어떻게 사용하시는지 궁금합니다 ..
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
패키지 의존성을 확인해보는법?
해당 챕터를 들고 궁금한 점이 있어 문의를 남깁니다. 7분를 들어보면 패키지 의존성을 확인해보라는 말이 나오는데 그런 의존성을 파악하는 툴 같은게 있는건가요?
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
중첩 라우트
그럼 중첩 라우트는 인클루드 개념 인거겠네요?
-
미해결Practical Testing: 실용적인 테스트 가이드
환경변수 관련되서 여쭤볼게 있습니다~
mock 테스트 중에환경변수(@Value)를 가져와야하는데,@SpringBootTest가 아니라서 환경변수를 못가져오고 있습니다.그래서 환경변수를 담은 변수가 null이 나오기 때문에 테스트를 못하고 있는데, 이럴 경우 어떻게 하시나요??일단 환경변수 대신, 생성자를 통해 해당 변수들을 받는 형태로 리펙토링했는데, 프로덕션 코드들을 테스트에 맞추는 거 같아서 약간 딜레마가 오고있어요.선생님께서는 이런 경우 어떻게 하시나요?1. 환경변수 이슈2. 프로덕션 코드를 테스트코드에 맞추는 리펙토링(2번은 수업에 있네요 ㅎㅎ)
-
해결됨Practical Testing: 실용적인 테스트 가이드
TestFixture에 질문이 있습니다.
테스트에서 사용하는 빌더 매서드를 한 곳에 모아놓으면 오히려 유지보수가 어렵고 매번 새롭게 만들게 된다고 하셨습니다. 그리고 매서드를 만들때 테스트 검증이나 테스트에 필요한 인수만 외부로 들어내서 테스트의 목적을 명확하게 들어내는게 좋다고 하셨는데 만약 테스트 케이스마다 외부로 들어내는게 제각각 다른 경우에 하나의 테스트 클래스에 다양한 빌더 매서드들이 생기게 된다면 그것도 관리하는데 어려움이 발생할 거라 생각합니다. 이런 경우에는 하나의 빌더 매서드만 생성해서 사용하시나요 ?아니면 그렇게 많이 발생할 일이 없기 때문에 매번 테스트에 필요한 빌더 매서드들을 만드시나요?
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
도메인 객체와 영속성 객체를 구분하게 되면
도메인 객체와 영속성 객체를 구분하게 되면 비즈니스 로직을 짤때 JPA에서 제공해주는 기능들을 사용하지 못할거 같은데 제가 이해한 방식들이 맞나요??예를들어 User의 update 메소드를 확인해보면 기존 JPA에서 repository로 영속성 객체를 가져와서 값을 수정하는 방식이 아닌 완전히 새로운 User 객체를 생성하고 repository로 save 하는 방식으로 구현을 하시길래 그러면 JPA에서 영속성 객체들 끼리 단방향 매핑이나 양방향 매핑을 구현한 객체들은 도메인 객체로 어떻게 연결지어야할지 감이 안잡히네요..
-
미해결Practical Testing: 실용적인 테스트 가이드
스프링 부트 3.x 질문
현재 스프링 부트가 3.x 이상만 지원하고 있는데자바 17 스프링 부트 3.x 최신버전으로 들어도 문제 없을까요??