From 790dfe27d150e31a9d911913931e49d8d2518035 Mon Sep 17 00:00:00 2001 From: seokrae Date: Fri, 12 Nov 2021 21:45:10 +0900 Subject: [PATCH 1/4] =?UTF-8?q?spring-toby-3=20[Spring]=202=20=EC=B4=88?= =?UTF-8?q?=EB=82=9C=EA=B0=90=20DAO=20(2.3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 8 ++++++++ .../java/com/example/chapter1/part2/UserDao.java | 13 ++++++++++++- .../com/example/chapter1/part2/UserDaoTest.java | 8 ++++++-- .../com/example/chapter2/Chapter2Application.java | 11 +++++++++++ settings.gradle | 1 + 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 chapter2/src/main/java/com/example/chapter2/Chapter2Application.java diff --git a/build.gradle b/build.gradle index cb479ac..d479146 100644 --- a/build.gradle +++ b/build.gradle @@ -67,4 +67,12 @@ project(":chapter1") { runtimeOnly 'mysql:mysql-connector-java' testImplementation 'org.springframework.boot:spring-boot-starter-test' } +} +project(":chapter2") { + dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + runtimeOnly 'mysql:mysql-connector-java' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + } } \ No newline at end of file diff --git a/chapter1/src/main/java/com/example/chapter1/part2/UserDao.java b/chapter1/src/main/java/com/example/chapter1/part2/UserDao.java index 4463e3b..6eaa1c3 100644 --- a/chapter1/src/main/java/com/example/chapter1/part2/UserDao.java +++ b/chapter1/src/main/java/com/example/chapter1/part2/UserDao.java @@ -44,7 +44,18 @@ public User get(String id) throws SQLException { } } - public void del() throws SQLException { + public int getCount() throws SQLException { + try ( + Connection c = dataSource.getConnection(); + PreparedStatement ps = c.prepareStatement("SELECT COUNT(*) FROM USERS"); + ) { + ResultSet rs = ps.executeQuery(); + rs.next(); + return rs.getInt(1); + } + } + + public void truncateTable() throws SQLException { try ( Connection c = dataSource.getConnection(); Statement s = c.createStatement() diff --git a/chapter1/src/test/java/com/example/chapter1/part2/UserDaoTest.java b/chapter1/src/test/java/com/example/chapter1/part2/UserDaoTest.java index ecd6081..27fd8e2 100644 --- a/chapter1/src/test/java/com/example/chapter1/part2/UserDaoTest.java +++ b/chapter1/src/test/java/com/example/chapter1/part2/UserDaoTest.java @@ -23,8 +23,12 @@ class UserDaoTest { @DisplayName("DataSource 인터페이스를 사용한 테스트") @Test void testCase1() throws SQLException { + UserDao userDao = new UserDao(dataSource); + userDao.truncateTable(); + assertThat(userDao.getCount()).isZero(); + User actual = new User(); actual.setId("user_id"); actual.setName("user_name"); @@ -32,9 +36,9 @@ void testCase1() throws SQLException { userDao.add(actual); - User expected = userDao.get("user_id"); + assertThat(userDao.getCount()).isOne(); - userDao.del(); + User expected = userDao.get("user_id"); assertThat(actual).isEqualTo(expected); } diff --git a/chapter2/src/main/java/com/example/chapter2/Chapter2Application.java b/chapter2/src/main/java/com/example/chapter2/Chapter2Application.java new file mode 100644 index 0000000..ef55e46 --- /dev/null +++ b/chapter2/src/main/java/com/example/chapter2/Chapter2Application.java @@ -0,0 +1,11 @@ +package com.example.chapter2; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Chapter2Application { + public static void main(String[] args) { + SpringApplication.run(Chapter2Application.class, args); + } +} diff --git a/settings.gradle b/settings.gradle index de88464..854d314 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ rootProject.name = 'spring-toby' include 'chapter1' +include 'chapter2' From 5a221e8159e8577ed9bd51d9a9ab4f43b32582b1 Mon Sep 17 00:00:00 2001 From: seokrae Date: Sat, 13 Nov 2021 01:00:22 +0900 Subject: [PATCH 2/4] =?UTF-8?q?spring-toby-3=20[Spring]=202=20=EC=B4=88?= =?UTF-8?q?=EB=82=9C=EA=B0=90=20DAO=20(2.3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 +- .../chapter2/config/DataSourceConfig.java | 23 +++++ .../com/example/chapter2/dao/UserDao.java | 72 +++++++++++++++ .../com/example/chapter2/domain/User.java | 24 +++++ chapter2/src/main/resources/application.yml | 17 ++++ .../src/main/resources/docker-compose.yml | 17 ++++ chapter2/src/main/resources/schema.sql | 7 ++ .../com/example/chapter2/dao/UserDaoTest.java | 87 +++++++++++++++++++ .../src/test/resources/application-test.yml | 19 ++++ chapter2/src/test/resources/schema.sql | 7 ++ 10 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 chapter2/src/main/java/com/example/chapter2/config/DataSourceConfig.java create mode 100644 chapter2/src/main/java/com/example/chapter2/dao/UserDao.java create mode 100644 chapter2/src/main/java/com/example/chapter2/domain/User.java create mode 100644 chapter2/src/main/resources/application.yml create mode 100644 chapter2/src/main/resources/docker-compose.yml create mode 100644 chapter2/src/main/resources/schema.sql create mode 100644 chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java create mode 100644 chapter2/src/test/resources/application-test.yml create mode 100644 chapter2/src/test/resources/schema.sql diff --git a/build.gradle b/build.gradle index d479146..e9860df 100644 --- a/build.gradle +++ b/build.gradle @@ -70,8 +70,10 @@ project(":chapter1") { } project(":chapter2") { dependencies { + // Driver.class 호출하기 위한 implementation 설정 + implementation 'mysql:mysql-connector-java' + implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'mysql:mysql-connector-java' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/chapter2/src/main/java/com/example/chapter2/config/DataSourceConfig.java b/chapter2/src/main/java/com/example/chapter2/config/DataSourceConfig.java new file mode 100644 index 0000000..af78b37 --- /dev/null +++ b/chapter2/src/main/java/com/example/chapter2/config/DataSourceConfig.java @@ -0,0 +1,23 @@ +package com.example.chapter2.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceConfig { + + @Bean + public DataSource dataSource() { + SimpleDriverDataSource dataSource = new SimpleDriverDataSource(); + + dataSource.setDriverClass(com.mysql.cj.jdbc.Driver.class); + dataSource.setUrl("jdbc:mysql://localhost:3309/user-db"); + dataSource.setUsername("root"); + dataSource.setPassword("1234"); + + return dataSource; + } +} diff --git a/chapter2/src/main/java/com/example/chapter2/dao/UserDao.java b/chapter2/src/main/java/com/example/chapter2/dao/UserDao.java new file mode 100644 index 0000000..a10d73c --- /dev/null +++ b/chapter2/src/main/java/com/example/chapter2/dao/UserDao.java @@ -0,0 +1,72 @@ +package com.example.chapter2.dao; + +import com.example.chapter2.domain.User; +import org.springframework.dao.EmptyResultDataAccessException; + +import javax.sql.DataSource; +import java.sql.*; + +public class UserDao { + + private final DataSource dataSource; + + public UserDao(DataSource dataSource) { + this.dataSource = dataSource; + } + + public void add(User user) throws SQLException { + try ( + Connection c = dataSource.getConnection(); + PreparedStatement ps = c.prepareStatement("INSERT INTO USERS(id, name, password) values (?, ?, ?)") + ) { + ps.setString(1, user.getId()); + ps.setString(2, user.getName()); + ps.setString(3, user.getPassword()); + + ps.executeUpdate(); + } + } + + public User get(String id) throws SQLException { + try ( + Connection c = dataSource.getConnection(); + PreparedStatement ps = c.prepareStatement("SELECT * FROM USERS WHERE id = ?") + ) { + ps.setString(1, id); + ResultSet rs = ps.executeQuery(); + + User user = null; + + if(rs.next()) { + user.setId(rs.getString("id")); + user.setName(rs.getString("name")); + user.setPassword(rs.getString("password")); + } + + if(user == null) { + throw new EmptyResultDataAccessException(1); + } + return user; + } + } + + public int getCount() throws SQLException { + try ( + Connection c = dataSource.getConnection(); + PreparedStatement ps = c.prepareStatement("SELECT COUNT(*) FROM USERS"); + ) { + ResultSet rs = ps.executeQuery(); + rs.next(); + return rs.getInt(1); + } + } + + public void truncateTable() throws SQLException { + try ( + Connection c = dataSource.getConnection(); + Statement s = c.createStatement() + ) { + s.executeUpdate("TRUNCATE TABLE USERS"); + } + } +} diff --git a/chapter2/src/main/java/com/example/chapter2/domain/User.java b/chapter2/src/main/java/com/example/chapter2/domain/User.java new file mode 100644 index 0000000..1e3cc06 --- /dev/null +++ b/chapter2/src/main/java/com/example/chapter2/domain/User.java @@ -0,0 +1,24 @@ +package com.example.chapter2.domain; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.relational.core.mapping.Table; + +@Table(value = "USERS") +@Setter +@Getter +@EqualsAndHashCode(of = "id") +@NoArgsConstructor +public class User { + private String id; + private String name; + private String password; + + public User(String id, String name, String password) { + this.id = id; + this.name = name; + this.password = password; + } +} diff --git a/chapter2/src/main/resources/application.yml b/chapter2/src/main/resources/application.yml new file mode 100644 index 0000000..edf32ca --- /dev/null +++ b/chapter2/src/main/resources/application.yml @@ -0,0 +1,17 @@ +server: + port: 8000 + +spring: + profiles: + active: local + + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3309/user-db + username: root + password: 1234 + + sql: + init: + mode: always + schema-locations: schema.sql diff --git a/chapter2/src/main/resources/docker-compose.yml b/chapter2/src/main/resources/docker-compose.yml new file mode 100644 index 0000000..7006bf1 --- /dev/null +++ b/chapter2/src/main/resources/docker-compose.yml @@ -0,0 +1,17 @@ +version: '3' + +services: + n-db: + image: mysql:latest + container_name: n-db + restart: always + ports: + - "3309:3306" + environment: + - MYSQL_DATABASE=user-db + - MYSQL_ROOT_PASSWORD=1234 + - TZ=Asia/Seoul + command: + - --default-authentication-plugin=mysql_native_password + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci \ No newline at end of file diff --git a/chapter2/src/main/resources/schema.sql b/chapter2/src/main/resources/schema.sql new file mode 100644 index 0000000..a7e4a09 --- /dev/null +++ b/chapter2/src/main/resources/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS USERS +( + id varchar(10), + name varchar(20) not null, + password varchar(20) not null, + primary key (id) +); \ No newline at end of file diff --git a/chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java b/chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java new file mode 100644 index 0000000..b3c54cc --- /dev/null +++ b/chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java @@ -0,0 +1,87 @@ +package com.example.chapter2.dao; + +import com.example.chapter2.config.DataSourceConfig; +import com.example.chapter2.domain.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import javax.sql.DataSource; +import java.sql.SQLException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {DataSourceConfig.class}) +class UserDaoTest { + + @Autowired + private DataSource dataSource; + private UserDao userDao; + private User user1; + private User user2; + private User user3; + + @BeforeEach + void setUp() throws SQLException { + userDao = new UserDao(dataSource); + userDao.truncateTable(); + + user1 = new User("user_0", "user_name_0", "1234"); + user2 = new User("user_1", "user_name_1", "1234"); + user3 = new User("user_2", "user_name_2", "1234"); + } + + @DisplayName("테이블 데이터 등록 및 조회 테스트") + @Test + void testCase1() throws SQLException { + assertThat(userDao.getCount()).isZero(); + + userDao.add(user1); + userDao.add(user2); + assertThat(userDao.getCount()).isEqualTo(2); + + User expected1 = userDao.get(user1.getId()); + assertThat(user1.getName()).isEqualTo(expected1.getName()); + + User expected2 = userDao.get(user2.getId()); + assertThat(user2.getName()).isEqualTo(expected2.getName()); + } + + @DisplayName("테이블 등록 카운트 테스트") + @Test + void testCase2() throws SQLException { + assertThat(userDao.getCount()).isZero(); + + userDao.add(user1); + assertThat(userDao.getCount()).isOne(); + + userDao.add(user2); + assertThat(userDao.getCount()).isEqualTo(2); + + userDao.add(user3); + assertThat(userDao.getCount()).isEqualTo(3); + + User actual = userDao.get("user_1"); + + assertThat(actual.getName()).isEqualTo("user_name_1"); + } + + @DisplayName("데이터 액세스 예외 테스트") + @Test + void testCase3() throws SQLException { + assertThat(userDao.getCount()).isZero(); + + userDao.add(user1); + + assertThatExceptionOfType(EmptyResultDataAccessException.class) + .isThrownBy(() -> userDao.get("111")); + } +} \ No newline at end of file diff --git a/chapter2/src/test/resources/application-test.yml b/chapter2/src/test/resources/application-test.yml new file mode 100644 index 0000000..a9cca0a --- /dev/null +++ b/chapter2/src/test/resources/application-test.yml @@ -0,0 +1,19 @@ +server: + port: 8000 + +spring: + profiles: + active: local + + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3309/user-db + username: root + password: 1234 + +logging: + level: + org: + hibernate: + sql: debug + type: trace diff --git a/chapter2/src/test/resources/schema.sql b/chapter2/src/test/resources/schema.sql new file mode 100644 index 0000000..a7e4a09 --- /dev/null +++ b/chapter2/src/test/resources/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS USERS +( + id varchar(10), + name varchar(20) not null, + password varchar(20) not null, + primary key (id) +); \ No newline at end of file From d31046c72df9f0cadad3bad615a8af464eb182b1 Mon Sep 17 00:00:00 2001 From: seokrae Date: Sat, 13 Nov 2021 09:59:03 +0900 Subject: [PATCH 3/4] =?UTF-8?q?spring-toby-3=20[Spring]=202=20=EC=B4=88?= =?UTF-8?q?=EB=82=9C=EA=B0=90=20DAO=20(2.3=20-=20code=20fix)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter2/src/main/java/com/example/chapter2/dao/UserDao.java | 1 + chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java | 1 + 2 files changed, 2 insertions(+) diff --git a/chapter2/src/main/java/com/example/chapter2/dao/UserDao.java b/chapter2/src/main/java/com/example/chapter2/dao/UserDao.java index a10d73c..4b5449c 100644 --- a/chapter2/src/main/java/com/example/chapter2/dao/UserDao.java +++ b/chapter2/src/main/java/com/example/chapter2/dao/UserDao.java @@ -38,6 +38,7 @@ public User get(String id) throws SQLException { User user = null; if(rs.next()) { + user = new User(); user.setId(rs.getString("id")); user.setName(rs.getString("name")); user.setPassword(rs.getString("password")); diff --git a/chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java b/chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java index b3c54cc..a7cb2a0 100644 --- a/chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java +++ b/chapter2/src/test/java/com/example/chapter2/dao/UserDaoTest.java @@ -42,6 +42,7 @@ void setUp() throws SQLException { @DisplayName("테이블 데이터 등록 및 조회 테스트") @Test void testCase1() throws SQLException { + assertThat(userDao.getCount()).isZero(); userDao.add(user1); From 69c81a289d2095d1b08ee98fbbcfa0b260a5e350 Mon Sep 17 00:00:00 2001 From: seokrae Date: Sat, 13 Nov 2021 19:31:58 +0900 Subject: [PATCH 4/4] =?UTF-8?q?spring-toby-3=20[Spring]=202=20=EC=B4=88?= =?UTF-8?q?=EB=82=9C=EA=B0=90=20DAO=20(2.4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/JUnitApplicationContextTest.java | 51 +++++++++++++++++++ .../chapter2/test/PracticeFrameworkTest.java | 24 +++++++++ 2 files changed, 75 insertions(+) create mode 100644 chapter2/src/test/java/com/example/chapter2/test/JUnitApplicationContextTest.java create mode 100644 chapter2/src/test/java/com/example/chapter2/test/PracticeFrameworkTest.java diff --git a/chapter2/src/test/java/com/example/chapter2/test/JUnitApplicationContextTest.java b/chapter2/src/test/java/com/example/chapter2/test/JUnitApplicationContextTest.java new file mode 100644 index 0000000..0281cf5 --- /dev/null +++ b/chapter2/src/test/java/com/example/chapter2/test/JUnitApplicationContextTest.java @@ -0,0 +1,51 @@ +package com.example.chapter2.test; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; + +import java.util.HashSet; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +@ContextConfiguration +class JUnitApplicationContextTest { + // 테스트 컨텍스트가 매번 주입해주는 애플리케이션 컨텍스트는 항상 같은 오브젝트인지 테스트로 확인 + @Autowired + private ApplicationContext context; + static Set testObjects = new HashSet<>(); + static ApplicationContext contextObject = null; + + @DisplayName("애플리케이션 컨텍스트가 context 변수에 주입되었는지 확인하는 테스트") + @Test + void testCase1() { + assertThat(testObjects).doesNotHaveSameClassAs(this); + testObjects.add(this); + + assertThat(contextObject == null || contextObject == this.context).isTrue(); + contextObject = this.context; + } + + @DisplayName("애플리케이션 컨텍스트가 context 변수에 주입되었는지 확인하는 테스트") + @Test + void testCase2() { + assertThat(testObjects).doesNotHaveSameClassAs(this); + testObjects.add(this); + + assertThat(contextObject == null || contextObject == this.context).isTrue(); + contextObject = this.context; + } + + @DisplayName("애플리케이션 컨텍스트가 context 변수에 주입되었는지 확인하는 테스트") + @Test + void testCase3() { + assertThat(testObjects).doesNotHaveSameClassAs(this); + testObjects.add(this); + + // assertThat(contextObject, either(is(nullValue())).or(is(this.context))); + // contextObject = this.context; + } +} diff --git a/chapter2/src/test/java/com/example/chapter2/test/PracticeFrameworkTest.java b/chapter2/src/test/java/com/example/chapter2/test/PracticeFrameworkTest.java new file mode 100644 index 0000000..1a4b62d --- /dev/null +++ b/chapter2/src/test/java/com/example/chapter2/test/PracticeFrameworkTest.java @@ -0,0 +1,24 @@ +package com.example.chapter2.test; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.RepeatedTest; + +import java.util.HashSet; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * JUnit은 테스트 실행 시 각 메서드 마다 새로운 테스트 오브젝트를 만든다. + */ +class PracticeFrameworkTest { + static Set testObjects = + new HashSet<>(); + + @DisplayName("JUnit이 매번 새로운 테스트 오브젝트를 만든다는 사실을 검증하는 테스트") + @RepeatedTest(value = 3, name = "{currentRepetition} / {totalRepetitions}") + void testCase1() { + assertThat(testObjects).doesNotHaveSameClassAs(this); + testObjects.add(this); + } +}