전체 글 361

JPA - Update(수정) 시 save() 메서드를 호출하는 것이 좋을까?

JPA를 사용하면 트랜잭션 범위 안에서 Dirty Checking이 동작한다. 따라서 save() 메서드를 호출하지 않아도 값이 알아서 수정되고 반영된다. 그렇다면 save()를 호출하는 것이랑 어떤 차이가 있는 지 알아보자. 차이 먼저 @Transactional만을 사용한 예제를 보자. @Transactional public Notice update(Long noticeId, String content) { Notice notice = noticeRepository.findById(noticeId).get(); notice.setContent(content); } 다음은 repository.save() 메서드를 사용한 예제를 보자. public Notice update(Long noticeId, Str..

Server/Spring JPA 2022.09.15

JPA - TestEntityManager를 활용한 Repository 테스트

Repository 테스트를 작성할 때 결과를 검증하기 위해서 어떤 도구를 사용해야 할까? 일반적으로 Repository.save() 기능을 테스트한다고 하면, Repository.find_을 사용해서 검증하기 쉽다. 하지만 이는 적절치 않다. 가령, userRepository를 테스트하는 코드에서 userRepository를 사용하면 First 원칙 중 I(Isolated - 고립성)이 깨지게 된다. 그래서 나는 JdbcTemplate을 사용했다. 기존의 코드 @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class AccountRepositoryTest { private AccountRe..

Server/JUnit, Spock 2022.09.14

JUnit5 - Controller Test에 BDD 적용하기 (+ Rest Docs)

MockMvc를 사용해서 Controller를 Test할 때 BDD를 적용해서 가독성을 향상시키는 방법에 대해 알아보자. 기존의 코드를 살펴보자. 기존 기존의 코드는 다음과 같았다. @Test @DisplayName("유저를 생성할 수 있다.") void signup() throws Exception { SignUpRequest signUpRequest = SignUpRequest.builder() .loginId("test123") .password("password12@") .name("TestName") .birthday(LocalDate.of(1994, 2, 10)) .phone("01012345678") .allowToMarketingNotification(true) .build(); mockM..

Server/JUnit, Spock 2022.09.14

SQL - OneToOne 관계일 때 주의할 점 (+ Unique Key 설정)

SQL에서 1:1 (OneToOne) 관계를 정의할 때 반드시 고려해야 하는 부분이 있다. 예시를 통해 살펴보자. 주어진 상황 아래는 내가 설계한 DB의 일부이다. 계정과 회원을 굳이 분리한 이유는 성격이 다르다고 생각해서이다. 계정은 회원 정보에 속하기 때문에 보안 등급이 더 높고, 다른 테이블에서 Join을 할 때 회원 정보는 필요하지만 계정 정보는 필요하지 않기 때문에 해당과 같이 설계하였다. 계정과 회원은 1:1 (OneToOne) 관계를 맺는다. 이때 중요한 것은 서로에 대한 참조 키에 Unieque key를 걸어줘야 한다는 점이다. Unieque key 위 DB를 기준으로, User 테이블의 account_id 컬럼에 Unique Key를 걸어줘야 비로소 1:1이 된다. Unique key 조..

Database/SQL 2022.09.08

Java - 배열(Array)을 사용할 때 주의해야 할 점! [+ 공변(Convaiant)]

나는 배열과 리스트의 차이가 '자원 공간이 동적인지의 여부'로 생각해왔다. 그래서 자원 공간이 정해져있는 경우에는 배열을 사용했고, 그렇지 않은 경우에는 리스트를 사용해왔다. 하지만 현재는 생각이 바뀌게 되었다. Array(배열) vs ArrayList(리스트) In Java Array와 ArrayList의 차이점을 간단하게 정리해보자. Array(배열) 사이즈가 정적인 데이터 구조 primitive 타입과 인스턴스 타입 모두 원소로 포함될 수 있다. Generic(제너릭)을 사용할 수 없다. 부수적인 내용 (길이를 구할때는 length 변수를 사용, 할당은 = 를 사용, ...) ArrayList(리스트) 사이즈가 동적인 데이터 구조 인스턴스만 원소로 포함될 수 있다. Generic(제너릭)을 지원한다..

Language/Java 2022.09.07

Java - 리플렉션 사용하기!

리플렉션은 구체적인 클래스 타입을 알지 못해도, 해당 클래스의 메소드나 타입, 변수 들에 접근할 수 있도록 해주는 자바 API이다. 리플렉션은 JVM이 클래스 로더를 통해 읽어온 클래스 정보(reflect된 정보)를 통해 접근한다. 리플렉션은 아래의 경우 사용한다. 특정 애노테이션이 붙어있 필드 또는 메소드를 읽어오기 특정 이름 패턴에 해당하는 메소드 목록 가져와 호출하기 ... 예시 리플렉션을 사용하면 문자열로 클래스를 만들 수 있다. 아래의 코드를 보자. Class HelloClass = Class.forName("jaehoney.blogcode.Hello"); 문자열(package name)를 사용해서 클래스 정보를 꺼내온다. 이후에 해당 클래스의 인스턴스를 만들 수도 있다. Constructor ..

Language/Java 2022.09.04

테스트 코드가 실제 코드에 영향을 줘선 안되는가 ?

많은 분들이 테스트 코드가 프로덕트 코드에 영향을 줘선 안된다고 알고 있을 것이다. 나 조차도 내가 개발한 코드는 절대 테스트 코드가 프로덕트 코드에 영향을 주지 않고 있다고 믿었다. 그러던 어느날, 회사 팀 동료 A가 나에게 이런 질문을 했다. 동료 A: Jerry! 서비스 테스트 코드를 작성할 떄 RequestDto가 필요한데, 해당 Dto는 getter만 열어뒀거든요. 서비스 테스트하려면 Builder나 Constructor를 만들어줘야 하나요?? Jerry(본인): (3분 정도 고민하다가..) 헐헐 그러네요!! 저는 테스트가 프로덕트 코드에 영향이 절대 없게 개발하는 것을 목표로 했었는데, 따지고 보면 생성자 조차도 필요 없는 것이네요..! 해당 질문으로 나는 완전 충격을 받았다. 상황 상황은 이..

JUnit5 - Nested Class를 사용해서 우아하게 서비스 테스트 작성하기!

서비스 단위 테스트(Unit Test)를 작성할 때 구조를 미리 잡는 것도 중요하다. 나중을 생각하지 않고 테스트 코드를 지저분하게 작성했을 때 본인이 혼자 개발한다면 적당한 시기에 리팩토링을 진행할 수 있다. 하지만, 여럿이서 협업을 진행하다 보면 잠깐 자리를 비운 사이 다른 사람이 지저분한 구조를 계속 가져가면서 코드를 많이 작성해서 겉잡기가 힘들어질 수 있다. 해당 포스팅에서는 Nested 클래스를 사용해서 서비스 테스트를 우아하게 작성하는 방법에 대해 다룬다. Nested Tests JUnit5에서는 @Nested 애노테이션을 사용해서 테스트 간 인스턴스와 상태, 설정을 공유할 수 있다. 이를 사용하면 테스트를 더 우아하게 작성할 수 있다. 회원가입 기능을 테스트한다고 가정해보자. 기존의 테스트 ..

Server/JUnit, Spock 2022.09.03

Effective Java - 추상 클래스와 인터페이스 차이

Java 8부터 인터페이스도 default method를 제공할 수 있게 되었다. 즉, 추상 클래스와 인터페이스 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다. Effective Java에서는 '가능한' 추상클래스가 아닌 인터페이스를 활용하는 것을 권장한다. 그 차이는 무엇인지 알아보자. Abstract Class vs Interface 해당 두 가지 개념의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바는 단일 상속만 지원하니, 추상 클래스 방식은 새로운 타입을 정의하는 데 커다란 제약을 안게 되는 것이다. 반면, 인터페이스를 구현하면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 기존 클래스에도 손쉽게 새로운 ..

Language/Java 2022.09.02

Effective Java - Comparable을 잘 구현하는 방법!

Comparable Java로 알고리즘 공부를 하는 사람이라면 Comparable을 매우 자주 사용하게 된다. Comparable을 구현하면 인스턴스들의 순서를 손쉽게 정할 수 있다. 문제는 Comparable을 구현하는 방법을 잊어먹는 경우가 많다. 이는 Comporable 구현이 어렵기 때문이다. 예시 일반적으로 Comparable을 사용하는 예시를 살펴보자. class Point implements Comparable { int x, y, z; @Override public int compareTo(Point p) { if(this.x > p.x) { return 1; } else if(this.x == p.x) { if(this.y > p.y) { return 1; } else if(this.y ..

Language/Java 2022.09.01