반응형
오늘은 23, 24강 Controller Test를 공부해보았다.
각 클래스의 불필요한 부분들을 정리하고 있다.
*JsonConfig
package com.fastcampus.javaallinone.project3.mycontact.configuration;
import com.fastcampus.javaallinone.project3.mycontact.configuration.serializer.BirthdaySerializer;
import com.fastcampus.javaallinone.project3.mycontact.domain.dto.Birthday;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@Configuration
public class JsonConfig {
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper){
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper);
return converter;
}
@Bean
public ObjectMapper objectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new BirthdayModule());
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
static class BirthdayModule extends SimpleModule{
BirthdayModule(){
super();
addSerializer(Birthday.class, new BirthdaySerializer());
}
}
}
*PersonDto
package com.fastcampus.javaallinone.project3.mycontact.controller.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@Data
@NoArgsConstructor
@AllArgsConstructor(staticName = "of")
public class PersonDto {
private String name;
private String hobby;
private String address;
private LocalDate birthday;
private String job;
private String phoneNumber;
}
*PersonController
package com.fastcampus.javaallinone.project3.mycontact.controller;
import com.fastcampus.javaallinone.project3.mycontact.controller.dto.PersonDto;
import com.fastcampus.javaallinone.project3.mycontact.domain.Person;
import com.fastcampus.javaallinone.project3.mycontact.repository.PersonRepository;
import com.fastcampus.javaallinone.project3.mycontact.service.PersonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@RequestMapping(value = "/api/person")
@RestController
@Slf4j
public class PersonController {
@Autowired
private PersonService personService;
@Autowired
private PersonRepository personRepository;
@GetMapping("/{id}")
public Person getPerson(@PathVariable Long id){
return personService.getPerson(id);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void postPerson(@RequestBody Person person) {
personService.put(person);
}
@PutMapping("/{id}")
public void modifyPerson(@PathVariable Long id, @RequestBody PersonDto personDto){
personService.modify(id, personDto);
}
@PatchMapping("/{id}")
public void modifyPerson(@PathVariable Long id, String name){
personService.modify(id, name);
}
@DeleteMapping("/{id}")
public void deletePerson(@PathVariable Long id){
personService.delete(id);
}
}
*Birthday
package com.fastcampus.javaallinone.project3.mycontact.domain.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Embeddable;
import java.time.LocalDate;
// Entitiy 에 속해있는 DTO라는 것을 표시
@Embeddable
@NoArgsConstructor
@Data
public class Birthday {
private Integer yearOfBirthday;
private Integer monthOfBirthday;
private Integer dayOfBirthday;
private Birthday(LocalDate birthday) {
this.yearOfBirthday = birthday.getYear();
this.monthOfBirthday = birthday.getMonthValue();
this.dayOfBirthday = birthday.getDayOfMonth();
}
public static Birthday of(LocalDate birthday){
return new Birthday(birthday);
}
}
*Person
package com.fastcampus.javaallinone.project3.mycontact.domain;
import com.fastcampus.javaallinone.project3.mycontact.controller.dto.PersonDto;
import com.fastcampus.javaallinone.project3.mycontact.domain.dto.Birthday;
import lombok.*;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.Where;
import org.springframework.util.StringUtils;
import javax.persistence.*;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.time.LocalDate;
@Entity
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@Data
@Where(clause = "deleted = false")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NonNull
@NotEmpty
@Column(nullable = false)
private String name;
private String hobby;
private String address;
@Valid
@Embedded
private Birthday birthday;
private String job;
private String phoneNumber;
@ColumnDefault("0") //0=false
private boolean deleted;
public void set(PersonDto personDto){
if(!StringUtils.isEmpty(personDto.getHobby())){
this.setHobby(personDto.getHobby());
}
if(!StringUtils.isEmpty(personDto.getAddress())){
this.setAddress(personDto.getAddress());
}
if(!StringUtils.isEmpty(personDto.getJob())){
this.setJob(personDto.getJob());
}
if(!StringUtils.isEmpty(personDto.getPhoneNumber())){
this.setPhoneNumber(personDto.getPhoneNumber());
}
if(personDto.getBirthday() != null){
this.setBirthday(Birthday.of(personDto.getBirthday()));
}
}
public Integer getAge(){
if(this.birthday != null){
return LocalDate.now().getYear() - this.getBirthday().getYearOfBirthday() + 1;
}else{
return null;
}
}
public boolean isBirthdayToday(){
return LocalDate.now().equals(LocalDate.of(this.getBirthday().getYearOfBirthday()
, this.getBirthday().getMonthOfBirthday()
, this.getBirthday().getDayOfBirthday()));
}
}
*PersonRepository
package com.fastcampus.javaallinone.project3.mycontact.repository;
import com.fastcampus.javaallinone.project3.mycontact.domain.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface PersonRepository extends JpaRepository<Person, Long> {
List<Person> findByName(String name);
// Entity 기반으로 쿼리를 실행시키는 것
@Query(value = "select person from Person person where person.birthday.monthOfBirthday = :monthOfBirthday ")
List<Person> findByMonthOfBirthday(@Param("monthOfBirthday") int monthOfBirthday);
@Query(value = "select * from Person person where person.deleted = true", nativeQuery = true)
List<Person> findPeopleDeleted();
}
*PersonService
package com.fastcampus.javaallinone.project3.mycontact.service;
import com.fastcampus.javaallinone.project3.mycontact.controller.dto.PersonDto;
import com.fastcampus.javaallinone.project3.mycontact.domain.Person;
import com.fastcampus.javaallinone.project3.mycontact.repository.PersonRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
@Service
@Slf4j
public class PersonService {
@Autowired
private PersonRepository personRepository;
public List<Person> getPeopleByName(String name){
// List<Person> people = personRepository.findAll();
//
// return people.stream().filter(person -> person.getName().equals(name)).collect(Collectors.toList());
return personRepository.findByName(name);
}
@Transactional
public Person getPerson(Long id){
// Person person = personRepository.findById(id).get();
Person person = personRepository.findById(id).orElse(null);
// System.out.println("person : " + person);
log.info("person ; {}", person); //log출력을 제한할 수 있는 장점이 있어서 print보다 많이 쓴다.
return person;
}
@Transactional
public void put(Person person){
personRepository.save(person);
}
@Transactional
public void modify(Long id, PersonDto personDto){
Person person = personRepository.findById(id).orElseThrow(() -> new RuntimeException("아이디가 존재하지 않습니다."));
if(!person.getName().equals(personDto.getName())){
throw new RuntimeException("이름이 다릅니다.");
}
person.set(personDto);
personRepository.save(person);
}
@Transactional
public void modify(Long id, String name){
Person person = personRepository.findById(id).orElseThrow(() -> new RuntimeException("아이디가 존재하지 않습니다."));
person.setName(name);
personRepository.save(person);
}
@Transactional
public void delete(Long id){
Person person = personRepository.findById(id).orElseThrow(() -> new RuntimeException("아이디가 존재하지 않습니다."));
person.setDeleted(true);
personRepository.save(person);
}
}
*PersonControllerTest
package com.fastcampus.javaallinone.project3.mycontact.controller;
import com.fastcampus.javaallinone.project3.mycontact.controller.dto.PersonDto;
import com.fastcampus.javaallinone.project3.mycontact.domain.Person;
import com.fastcampus.javaallinone.project3.mycontact.domain.dto.Birthday;
import com.fastcampus.javaallinone.project3.mycontact.repository.PersonRepository;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.util.NestedServletException;
import javax.transaction.Transactional;
import java.time.LocalDate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j
@SpringBootTest
@Transactional
class PersonControllerTest {
@Autowired
private PersonController personController;
@Autowired
private PersonRepository personRepository;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private MappingJackson2HttpMessageConverter messageConverter;
private MockMvc mockMvc;
//BeforeEach를 달면 매 테스트마다 한번씩 실행이 됨
@BeforeEach
void beforeEach(){
mockMvc = MockMvcBuilders.standaloneSetup(personController).setMessageConverters(messageConverter).build();
}
@Test
void getPerson() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders.get("/api/person/1"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("martin"))
.andExpect(jsonPath("hobby").isEmpty())
.andExpect(jsonPath("address").isEmpty())
.andExpect(jsonPath("$.birthday").value("1991-08-15"))
.andExpect(jsonPath("$.job").isEmpty())
.andExpect(jsonPath("$.phoneNumber").isEmpty())
.andExpect(jsonPath("$.deleted").value(false))
.andExpect(jsonPath("$.age").exists()) //숫자를 넣을 경우 연도가 바뀜에 따라 테스트가 실패할 수 있어서 존재여부만 확인함
.andExpect(jsonPath("$.birthdayToday").isBoolean());
}
@Test
void postPerson() throws Exception{
mockMvc.perform(
MockMvcRequestBuilders.post("/api/person")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content("{ \"name\": \"martin2\",\n" +
" \"age\": 20,\n" +
" \"bloodType\": \"A\"}"))
.andDo(print())
.andExpect(status().isCreated());
}
@Test
void modifyPerson() throws Exception{
PersonDto dto = PersonDto.of("martin", "programming", "판교", LocalDate.now(), "programmer", "010-1111-2222");
mockMvc.perform(
MockMvcRequestBuilders.put("/api/person/1")
.contentType(MediaType.APPLICATION_JSON_VALUE)
//수정하지 않는 항목도 들어있어야 결과값이 null로 바뀌지 않음
.content(toJsonString(dto)))
.andDo(print())
.andExpect(status().isOk());
Person result = personRepository.findById(1L).get();
assertAll(
() -> assertThat(result.getName()).isEqualTo("martin"),
() -> assertThat(result.getHobby()).isEqualTo("programming"),
() -> assertThat(result.getAddress()).isEqualTo("판교"),
() -> assertThat(result.getBirthday()).isEqualTo(Birthday.of(LocalDate.now())),
() -> assertThat(result.getJob()).isEqualTo("programmer"),
() -> assertThat(result.getPhoneNumber()).isEqualTo("010-1111-2222")
);
}
@Test
void modifyPersonIfNameIsDifferent() throws Exception{
PersonDto dto = PersonDto.of("james", "programming", "판교", LocalDate.now(), "programmer", "010-1111-2222");
assertThrows(NestedServletException.class, () ->
mockMvc.perform(
MockMvcRequestBuilders.put("/api/person/1")
.contentType(MediaType.APPLICATION_JSON_VALUE)
//수정하지 않는 항목도 들어있어야 결과값이 null로 바뀌지 않음
.content(toJsonString(dto)))
.andDo(print())
.andExpect(status().isOk()));
}
@Test
void modifyName() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders.patch("/api/person/1")
.param("name","martinModified"))
.andDo(print())
.andExpect(status().isOk());
assertThat(personRepository.findById(1L).get().getName()).isEqualTo("martinModified");
}
@Test
void deletePerson() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders.delete("/api/person/1"))
.andDo(print())
.andExpect(status().isOk());
assertTrue(personRepository.findPeopleDeleted().stream().anyMatch(person -> person.getId().equals(1L)));
}
private String toJsonString(PersonDto personDto) throws JsonProcessingException {
return objectMapper.writeValueAsString(personDto);
}
}
*PersonRepositoryTest
package com.fastcampus.javaallinone.project3.mycontact.repository;
import com.fastcampus.javaallinone.project3.mycontact.domain.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.transaction.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@Transactional
@SpringBootTest
class PersonRepositoryTest {
@Autowired
private PersonRepository personRepository;
@Test
void crud(){
Person person = new Person();
person.setName("john");
personRepository.save(person);
List<Person> result = personRepository.findByName("john");
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getName()).isEqualTo("john");
// assertThat(result.get(0).getAge()).isEqualTo(10);
}
@Test
void hashCodeAndEquals(){
Person person1 = new Person("martin");
Person person2 = new Person("martin");
System.out.println(person1.equals(person2));
System.out.println(person1.hashCode());
System.out.println(person2.hashCode());
Map<Person, Integer> map = new HashMap<>();
map.put(person1, person1.getAge());
System.out.println(map);
System.out.println(map.get(person2));
}
@Test
void findBirthdayBetween(){
List<Person> result = personRepository.findByMonthOfBirthday(8);
Person martin = new Person();
assertThat(result.size()).isEqualTo(2);
assertThat(result.get(0).getName()).isEqualTo("martin");
assertThat(result.get(1).getName()).isEqualTo("sophia");
}
}
*PersonServiceTest
package com.fastcampus.javaallinone.project3.mycontact.service;
import com.fastcampus.javaallinone.project3.mycontact.domain.Person;
import com.fastcampus.javaallinone.project3.mycontact.repository.PersonRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class personServiceTest {
@Autowired
private PersonService personService;
@Autowired
private PersonRepository personRepository;
@Test
void getPeopleByName(){
List<Person> result = personService.getPeopleByName("martin");
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getName()).isEqualTo("martin");
}
@Test
void getPerson(){
Person person = personService.getPerson(3L);
assertThat(person.getName()).isEqualTo("dennis");
}
}
패스트캠퍼스 강의: https://bit.ly/3ilMbIO
반응형
'언어공부 > JAVA&SPRING' 카테고리의 다른 글
[패스트캠퍼스 수강 후기] 자바 인강 100% 환급 챌린지 37회차 미션 (0) | 2020.09.15 |
---|---|
[패스트캠퍼스 수강 후기] 자바 인강 100% 환급 챌린지 36회차 미션 (0) | 2020.09.14 |
[패스트캠퍼스 수강 후기] 자바 인강 100% 환급 챌린지 34회차 미션 (0) | 2020.09.12 |
[패스트캠퍼스 수강 후기] 자바 인강 100% 환급 챌린지 33회차 미션 (0) | 2020.09.11 |
[패스트캠퍼스 수강 후기] 자바 인강 100% 환급 챌린지 32회차 미션 (0) | 2020.09.10 |
댓글