목록프로그래밍 (409)
쌓고 쌓다
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/KO6Mb/btsEEEkgHc4/eUvNUNy0hSKnYz7OU6cok0/img.png)
좋아요나 댓글 개수와 같이 게시글에 포함되는 정보를 이용하여 정렬하고자 할때 게시글 테이블에 개수를 나타내는 컬럼을 추가하여 댓글 삽입도하며 게시글의 좋아요수를 올리는 방식은 쉽게 구현이 가능할 것이다. 그러나 좋아요 개수를 정규화하여 따로 테이블을 빼놓지 않고 비정규화하여 컬럼으로두어 관리한다면 동시성 문제나 불일치 문제가 발생할 수 있다. 그래서 조인을 통해 게시글 좋아요 개수나 정렬등을 구현할 수 있지만 서브쿼리를 사용하고자 한다. Spring Data Jpa만 알았던 나는 이제서야. 복잡한 쿼리 조회는 QueryDSL을 통해 해결이 가능하다는걸 알았다..!! Poster 테이블에는 좋아요 수를 관리하는 컬럼은 없고 좋아요 테이블인 poster_like 테이블과 1:N 관계를 갖는 상황이다. 현재 ..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/Zyy0G/btsEngbXpLS/OhQX3DVCKxULhZicgruGo0/img.png)
컨트롤러에 @AuthenticationPrincipal이 있어 테스트 코드를 동작할때 인증이 필요한 상황이 발생했다. 그래서 SecurityContextHolder에 우리의 사용자 정보를 등록할 필요가 있다. UserDetails Mock 객체를 Authentication에 등록할 필요가 있다. 등록하면 @AuthenticationPrincipal에서 사용자 정보를 꺼내 쓴다. CommentControllerTest @WebMvcTest(value = {CommentController.class}) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class CommentControllerTest { @Autowired private WebApplicationConte..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/r9hJf/btsEkSVUx3D/ibhOVbbM5zm44g5enwfDAK/img.png)
저번에 Enum 타입 비교시에도 Expected랑 Actual은 똑같은 값이 나오는데 자꾸 다르다고 나와서 Enum의 name()으로 값을 반환해주니 동일 검증이 성공했었는데 마찬가지로 LocalDateTime도 값이 똑같이 나오는데 왜 다르다고 하는지... 문제가 발생했다. 설마설마... LocalDateTime도 String 형식으로 바꿔줘야하나 싶어서 LocalDateTime의 메서드를 찾아보니... 존재하길래 toString()으로 문자열로 변환하고 테스트 코드를 돌려봤다.. 역시나... 검증시 JSON 응답과 일치시키기위해 String으로 변환해주자 ^^ 영감 쓰 : https://stackoverflow.com/questions/64984082/java-lang-assertionerror-js..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/belVm6/btsEeKjYIxO/bSgVbQEItEdmVRvKTjiy11/img.png)
"/members/signup" 컨트롤러 테스트 코드 실행시 401 에러를 응답으로 준다... 이 매핑은 permitAll()을 해두었는데도 말이다. 원인은 @WebMvcTest 어노테이션에 있었다. 기본적으로 @Test 어노테이션이 붙는다면 Spring Security를 auto-configure한다고 되어 있다. @SpringBootTest와 달리 @WebMvcTest는 해당 컨트롤러 동작에 필요한 빈들만 등록하여 사용하기에 시큐리티는 제외되는것 같다. defaultSecurityFilterChain에 보면 모든 요청에 인증이 필요한게 기본 값이다. 그래서 Spring Security는 기본 설정으로 등록되기에 해당 매핑은 인증, 인가가 필요한 것이다. @WithMockUser를 통해 테스트시 필요한..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/9NB37/btsEa6VhjEY/ApRWvQGh2GxbrKErKkJMa1/img.png)
Response Body에 값이 담겨 있지 않는 문제가 발생했다. 컨트롤러 코드는 다음과 같았다. memberService에 addMember를 통해 반환된 MemberResponse를 body 응답으로 보낸다. 테스트 코드에 given을 사용하여 다음과 같이 signUpMember이 들어왔을때 memberResponse를 반환하도록 했다. /* SignUpMember signUpMember = new SignUpMember(); signUpMember.setName("새로운닉네임"); signUpMember.setLoginId("새로운아이디"); signUpMember.setLoginPwd("새로운비밀번호"); MemberResponse memberResponse = new MemberResponse(..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/bFyPXz/btsD0IgZSZh/sIQHJk5lqAH6jk4T0uAus1/img.png)
JPA를 사용하여 페이징 처리된 데이터를 응답 해보자. 먼저, 다음과 같은 URL로 API를 만들고자 한다. /locations/{locationId}/posters?page={페이지번호}&size={페이지크기}sort={정렬방법} page, size, sort의 값은 필수가 아니며 입력하지 않은 값에대해 기본 값을 설정할 예정이다. locationId를 포함하는 poster들을 반환해주는 API이다. 컨트롤러로 들어온 요청의 쿼리파라미터를 처리할 클래스를 다음과 같이 하나 만들어 보자. PosterPageRequest package com.example.spotserver.dto.request; import jakarta.validation.constraints.Max; import jakarta.va..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/dvgJCj/btsD4GaML4q/KdkTfSIHow5vlxnZxbWOlk/img.png)
이상하게 컨트롤러에서 처리하지 못할 요청에 대해 404 에러가 안뜨고 401 에러가 뜨는 것이다. Controller에서 매핑하지 않은 요청에 대해 404 NOT FOUND 에러가 안뜨고 내가 예외 처리한 401 에러가 뜬다..! 왜일까? 결론은 스프링부트에서 에러 처리시 Forward인지.. Redirect인지.. 어떤 방식으로 /error로 요청을 보낸다. /error 매핑에서 에러를 처리하여 다음과 같이 JSON 또는 HTML로 응답을 내려주는것이다. 그렇다 현재 /error에 대해서도 Authentication이 적용되기 때문에 인증이 필요하다고 401 에러가 뜨는 것이다. 그런데 GET 요청은 모두 permitAll을 해두었지만 이상하게 401 에러가 뜨긴뜬다... 의문! 보니깐 직접 /err..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/uMDHX/btsD4unH3VL/9PFE9OT2svuZEIeXanlLB0/img.png)
API를 작성하고 매번 POSTMAN으로 요청과 응답을 확인해보는 과정은 시간도 많이 들고 번거롭다. 어떤 코드의 수정이나 추가가 일어났을때 모든 시스템의 API가 정상적으로 돌아가는지 확인하기 위해 테스트 코드를 작성해보자. MockMvc를 설정하고 초기화 시키는 코드는 다음과 같다. @SpringBootTest @Transactional @TestInstance(TestInstance.Lifecycle.PER_CLASS) class MemberControllerTest { private MockMvc mockMvc; @Autowired private WebApplicationContext webApplicationContext; @BeforeAll public void beforeAll() throw..