<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Jiruen.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 23 Feb 2025 16:06:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Jiruen.log</title>
            <url>https://velog.velcdn.com/images/rosie_98/profile/72e783de-0636-4d3c-9e4e-870726731df3/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Jiruen.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/rosie_98" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[ShiftM] 연차 연관관계 ]]></title>
            <link>https://velog.io/@rosie_98/ShiftM-%EC%97%B0%EC%B0%A8-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@rosie_98/ShiftM-%EC%97%B0%EC%B0%A8-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84</guid>
            <pubDate>Sun, 23 Feb 2025 16:06:46 GMT</pubDate>
            <description><![CDATA[<h2 id="🔎-연차-엔티티-연관-관계">🔎 연차 엔티티 연관 관계</h2>
<h4 id="회원mem--연차-신청lvr--1--n">회원(MEM) : 연차 신청(LVR) = 1 : N</h4>
<ul>
<li><code>연차 신청</code> -&gt; 연관 관계 주인</li>
<li>회원은 여러 개 연차 신청할 수 있다. <ul>
<li>ex) 2월 13일 생리 휴가, 2월 20일 연차유급휴가 </li>
</ul>
</li>
</ul>
<hr>
<h4 id="연차lev--연차-신청lvr--1--n">연차(LEV) : 연차 신청(LVR) = 1 : N</h4>
<ul>
<li><p><code>연차 신청</code> -&gt; 연관 관계 주인</p>
</li>
<li><p>연차는 여러 개의 연차 신청을 가진다. </p>
<ul>
<li>ex) 연차유급휴가 총 2일(1월, 2월 개근) </li>
</ul>
</li>
<li><blockquote>
<p>3월 5일 연차 신청(1일) / 3월 21일 연차 사용(1일)</p>
</blockquote>
</li>
<li><p>요구 사항</p>
<ul>
<li><code>별도의 사업운영에 막대한 지장이 있는 경우가 아닌 이상 근로자가 원하는 시기에 사용 가능</code> 
  -&gt; <strong>당일 연차 사용 가능</strong></li>
<li>같은 날 <strong>여러 개 연차 신청 금지</strong></li>
<li>유효 기간이 지난 연차는 연차 신청 목록에서 조회 불가</li>
<li>추후 유효 기간 임박한 연차 알림 전송하도록 기능 추가</li>
</ul>
</li>
</ul>
<hr>
<h4 id="회원mem--연차lev--1--n">회원(MEM) : 연차(LEV) = 1 : N</h4>
<ul>
<li><code>연차</code> -&gt; 연관 관계 주인</li>
<li>회원은 여러 개 연차를 가진다. <ul>
<li>ex) 생리 휴가 1일(11월), 생리 휴가 1일 (12월) 월차 1일(11월) ... </li>
</ul>
</li>
</ul>
<hr>
<h4 id="연차-유형lvt--연차lev--1--n">연차 유형(LVT) : 연차(LEV) = 1 : N</h4>
<ul>
<li><code>연차</code> -&gt; 연관 관계 주인</li>
<li>연차 유형은 여러 개의 연차를 가진다. <ul>
<li>ex) <code>생리 휴가</code> -&gt; 11월 생리 휴가 / 12월 생리 휴가</li>
</ul>
</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[코테 자주 쓰는 자바 함수 정리]]></title>
            <link>https://velog.io/@rosie_98/%EC%BD%94%ED%85%8C-%ED%95%84%EC%88%98-%ED%95%A8%EC%88%98-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@rosie_98/%EC%BD%94%ED%85%8C-%ED%95%84%EC%88%98-%ED%95%A8%EC%88%98-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 02 Feb 2025 08:56:52 GMT</pubDate>
            <description><![CDATA[<h2 id="아스키-코드">아스키 코드</h2>
<blockquote>
<p>숫자로 된 문자를 숫자로 변환하는 법 </p>
</blockquote>
<pre><code>int num = &#39;0&#39; - 48;</code></pre><ul>
<li><code>a</code> : 97</li>
<li><code>z</code> : 122</li>
<li><code>A</code> : 65</li>
<li><code>Z</code> : 90</li>
<li><code>0</code> : 48</li>
<li><code>9</code> : 57</li>
</ul>
<h2 id="입력-받기">입력 받기</h2>
<pre><code>import java.io.*;


class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine();
    }
}</code></pre><h2 id="string">String</h2>
<h2 id="arrays">Arrays</h2>
<pre><code>int[] arr = {2, 40, 5, 39, 9};

// 오름차순 
Arrays.sort(arr);

// 내림차순 
Arrays.sort(arr, Collections.reverseOrder());

// 이진 탐색 (sorted 필수)
Arrays.binarySearch(arr1, 2);

// 리스트로 변환
List list = Arrays.asList(arr);
</code></pre><h2 id="list">List</h2>
<pre><code>import java.util.*;

List&lt;String&gt; list = new ArrayList&lt;&gt;();

// 특정 인덱스에 삽입
list.add(0, &quot;add&quot;);            

// 수정
list.set(1, &quot;set&quot;);

// 인덱스로 삭제
list.remove(1);

// 값 존재 유무 확인
list.contains(&quot;contains&quot;);        
list.indexOf(&quot;index&quot;);    // 없다면 -1 반환</code></pre><h2 id="point">Point</h2>
<blockquote>
<p>💡 BFS 문제 풀이 시, Point 객체 사용하면 편하다!</p>
</blockquote>
<pre><code>// 라이브러리 선언
import java.awt.*;

// 좌표 위치 생성
Point point = new Point(1, 1);

int x = point.x;
int y = point.y;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 쿠키 삭제 안된다?]]></title>
            <link>https://velog.io/@rosie_98/Spring-%EC%BF%A0%ED%82%A4-%EC%82%AD%EC%A0%9C-%EC%95%88%EB%90%9C%EB%8B%A4</link>
            <guid>https://velog.io/@rosie_98/Spring-%EC%BF%A0%ED%82%A4-%EC%82%AD%EC%A0%9C-%EC%95%88%EB%90%9C%EB%8B%A4</guid>
            <pubDate>Mon, 13 Jan 2025 03:16:25 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-발생">문제 발생</h2>
<h3 id="⌨️-코드">⌨️ 코드</h3>
<pre><code>public HttpServletResponse deleteTokenCookie(HttpServletResponse response, String token) {
        ResponseCookie cookie = ResponseCookie.from(COOKIE_NAME, token)
                .maxAge(0)
                .build();
        response.addHeader(&quot;Set-Cookie&quot;, cookie.toString());
        return response;
    }</code></pre><ul>
<li>maxAge를 0으로 설정한 뒤 응답 헤더에 반환</li>
</ul>
<h2 id="문제-원인">문제 원인</h2>
<h4 id="path-옵션-pathmypath">path 옵션 (path=/mypath)</h4>
<ul>
<li>설정한 경로나 그 경로의 하위 경로에 있는 페이지만 쿠키에 접근할 수 있다.</li>
<li>절대 경로이어야 하고, (미 지정시) 기본값은 현재 경로이다.</li>
<li>사용 예시) path=/admin<ul>
<li>설정한 쿠키는 /admin과 그 하위 경로(/admin/something) 볼 수 있다.  </li>
<li>/home 이나 /adminpage에선 볼 수 없다.</li>
</ul>
</li>
<li>특별한 경우가 아니라면, path 옵션을 path=/같이 루트로 설정해 웹사이트의 모든 페이지에서 쿠키에 접근하는 것이 좋다.</li>
</ul>
<h2 id="문제-해결">문제 해결</h2>
<pre><code>public HttpServletResponse deleteTokenCookie(HttpServletResponse response, String token) {
        ResponseCookie cookie = ResponseCookie.from(COOKIE_NAME, null)
                .maxAge(0)
                .path(&quot;/&quot;)
                .build();
        response.addHeader(&quot;Set-Cookie&quot;, cookie.toString());
        return response;
    }</code></pre><ul>
<li>path 옵션 추가해주었더니 쿠키가 잘 삭제되었다!</li>
</ul>
<p>참고문헌
<a href="https://ko.javascript.info/cookie">https://ko.javascript.info/cookie</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AccessDeniedException]]></title>
            <link>https://velog.io/@rosie_98/AccessDeniedException</link>
            <guid>https://velog.io/@rosie_98/AccessDeniedException</guid>
            <pubDate>Sun, 12 Jan 2025 09:40:37 GMT</pubDate>
            <description><![CDATA[<h2 id="⛔️-accessdeniedexception-발생">⛔️ AccessDeniedException 발생</h2>
<ul>
<li>프론트와 백엔드 연동 작업을 하던 중 아래와 같은 에러가 발생</li>
<li>더 문제는 크롬 개발자 도구에 Network 탭엔 아무런 에러가 없다는 것...😵‍💫<pre><code>2025-01-12T18:34:47.162+09:00 ERROR 23113 --- [stard] [io-8080-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Unable to handle the Spring Security Exception because the response is already committed.] with root cause
</code></pre></li>
</ul>
<p>org.springframework.security.access.AccessDeniedException: Access Denied</p>
<p>...</p>
<p>2025-01-12T18:34:47.164+09:00 ERROR 23113 --- [stard] [io-8080-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] threw exception</p>
<p>org.springframework.security.access.AccessDeniedException: Access Denied</p>
<p>...</p>
<p>2025-01-12T18:34:47.165+09:00 ERROR 23113 --- [stard] [io-8080-exec-10] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing [ErrorPage[errorCode=0, location=/error]]</p>
<p>jakarta.servlet.ServletException: Unable to handle the Spring Security Exception because the response is already committed.</p>
<pre><code>


## 🤔 AccessDeniedException 원인

## 💡 AccessDeniedException 해결</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[IntelliJ] IntelliJ와 H2 연동하기]]></title>
            <link>https://velog.io/@rosie_98/IntelliJ-IntelliJ%EC%99%80-H2-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@rosie_98/IntelliJ-IntelliJ%EC%99%80-H2-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 04 Jun 2023 15:59:18 GMT</pubDate>
            <description><![CDATA[<h3 id="📣-oracle-database를-사용하고-있었지만-연결-오류가-발생하여-h2-database와-intellij를-연결시켜보자">📣 oracle Database를 사용하고 있었지만 연결 오류가 발생하여, H2 Database와 IntelliJ를 연결시켜보자!</h3>
<h2 id="📌-h2-설치-및-h2-실행하기">📌 H2 설치 및 H2 실행하기</h2>
<h4 id="1-h2-database-설치하기">1. H2 Database 설치하기</h4>
<ul>
<li><a href="https://www.h2database.com/html/main.html">https://www.h2database.com/html/main.html</a>
<img src="https://velog.velcdn.com/images/rosie_98/post/1713e885-9f78-4472-9d1b-b73678c3a037/image.png" alt=""></li>
</ul>
<h4 id="2-h2-실행하기">2. H2 실행하기</h4>
<ul>
<li>window인 경우 h2.bat를 
Mac인 경우 h2.sh를 클릭하여 H2 실행시키기
<img src="https://velog.velcdn.com/images/rosie_98/post/57cbfbed-9e34-4a43-a2c6-8e338899f891/image.png" alt=""></li>
</ul>
<h4 id="3-h2-database-생성하기">3. H2 database 생성하기</h4>
<ul>
<li><p>H2를 실행시키면 cmd창과 H2 콘솔창이 뜬다. </p>
<ul>
<li>이 때 주의할 점! cmd창을 닫게 되면 H2 접속 불가</li>
</ul>
</li>
<li><p>JDBC URL에 DB 명을 지정해 주자</p>
<ul>
<li>jdbc:h2:tcp://localhost/~/<strong>{DB 명}</strong>
<img src="https://velog.velcdn.com/images/rosie_98/post/6c14fa08-ceb0-478b-a07d-19f504951454/image.png" alt=""></li>
</ul>
</li>
<li><p>⛔ <strong>아래와 같은 오류가 발생한다면?</strong></p>
<blockquote>
<p>Database &quot;C:/Users/...&quot; not found, either pre-create it or allow remote database creation (not recommended in secure environments) [90149-200] 90149/90149 (도움말)</p>
</blockquote>
<ul>
<li>1) <strong>JDBC URL 명 변경</strong><ul>
<li>jdbc:h2:~/{DB 명}</li>
</ul>
</li>
<li>2) 변경 후, H2 콘솔에서 해당 DB 접속 시, JDBC URL를 <ul>
<li><strong>jdbc:h2:tcp://localhost/~/{DB 명}</strong> 으로 접속하기!</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="📌-intellij와-h2-연동하기">📌 IntelliJ와 H2 연동하기</h2>
<h4 id="1-intellij에-h2-database-등록하기">1. IntelliJ에 H2 database 등록하기</h4>
<ul>
<li><p>IntelliJ의 왼쪽, Database탭에서 Data Source 중 H2 선택하기 
<img src="https://velog.velcdn.com/images/rosie_98/post/df78904d-26df-4947-b8e5-53c5e1d98ec7/image.png" alt=""></p>
</li>
<li><p>User는 sa로, 
H2 콘솔에서 정한 DB 명을 Database에 작성하면 자동으로 URL에 반영된다.
<img src="https://velog.velcdn.com/images/rosie_98/post/ddfd5660-536c-420d-8895-a638e4d3a170/image.png" alt=""></p>
</li>
</ul>
<h4 id="2-applicationyml-에-h2-설정-등록">2. application.yml 에 H2 설정 등록</h4>
<pre><code>spring:
  datasource:         
    url:  jdbc:h2:tcp://localhost/~/{DB 명}
    username: sa
    password:
    driver-class-name: org.h2.Driver</code></pre><p><img src="https://velog.velcdn.com/images/rosie_98/post/20da1cd9-43ad-413b-9820-5bd1c0c93e0b/image.png" alt=""></p>
<h4 id="3-buildgradle-에-라이브러리-등록">3. build.gradle 에 라이브러리 등록</h4>
<blockquote>
<p>runtimeOnly &#39;com.h2database:h2&#39;</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[@GeneratedValue 적용해보자!]]></title>
            <link>https://velog.io/@rosie_98/GeneratedValue-%EC%A0%81%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@rosie_98/GeneratedValue-%EC%A0%81%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sun, 28 May 2023 08:36:59 GMT</pubDate>
            <description><![CDATA[<h3 id="span-stylecolor-es5s35userjavaspan"><span style="color: #es5s35">User.java</span></h3>
<blockquote>
<p>@SequenceGenerator(
        name = &quot;USER_SEQ_GENERATOR&quot;,
        sequenceName = &quot;USER_SEQ&quot;, 
        allocationSize = 1 
)</p>
</blockquote>
<blockquote>
<p>@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = &quot;USER_SEQ_GENERATOR&quot;)</p>
</blockquote>
<pre><code>@Data
@Setter
@Getter
@Entity
@SequenceGenerator(
        name = &quot;USER_SEQ_GENERATOR&quot;,
        sequenceName = &quot;USER_SEQ&quot;, 
        allocationSize = 1 
)
@Table(name = &quot;userInfo&quot;)
@SecondaryTable(name = &quot;LOGIN&quot;,
        pkJoinColumns = @PrimaryKeyJoinColumn(
                name = &quot;id&quot;, referencedColumnName = &quot;id&quot;))
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = &quot;USER_SEQ_GENERATOR&quot;)
    private Long id; // User Id

}</code></pre><blockquote>
<p>Hibernate: create sequence user_seq start with 1 increment by  1</p>
</blockquote>
<br>

<h3 id="span-stylebackground-color-es5s35applicationymlspan"><span style="background-color: #es5s35">application.yml</span></h3>
<pre><code>  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        show_sql: true
        format_sql: true</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[테스트 코드 실습 (학점 계산기 구현)]]></title>
            <link>https://velog.io/@rosie_98/%ED%95%99%EC%A0%90%EA%B3%84%EC%82%B0%EA%B8%B0-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@rosie_98/%ED%95%99%EC%A0%90%EA%B3%84%EC%82%B0%EA%B8%B0-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Thu, 25 May 2023 17:08:50 GMT</pubDate>
            <description><![CDATA[<h3 id="span-stylebackground-colorf2bed1🌁-요구사항span"><span style="background-color:#F2BED1">🌁 요구사항</span></h3>
<blockquote>
<ol>
<li><strong>평균 학점 계산 방법</strong> 
= (학점 수 x 교과목 평점)의 합계 / 수강 신청 총 학점 수</li>
<li><strong>일급 컬렉션 사용</strong></li>
</ol>
</blockquote>
<h3 id="span-stylebackground-colorf2bed1📂-학점-계산기-도메인span"><span style="background-color:#F2BED1">📂 학점 계산기 도메인</span></h3>
<blockquote>
<ul>
<li>이수한 과목( 객체지향프로그래밍, 자료구조, 중국어회화 )</li>
</ul>
</blockquote>
<ul>
<li>학점 계산기 </li>
</ul>
<h3 id="span-stylebackground-colorf2bed1🔗--흐름도span"><span style="background-color:#F2BED1">🔗  흐름도</span></h3>
<blockquote>
<ol>
<li>이수한 과목을 전달하여 평균학점 계산 요청 ---&gt; 학점 계산기</li>
<li>학점 계산기 ---&gt; (학점 수 x 교과목 평점)의 합계 / 수강신청 총 학점 수 </li>
<li>(학점 수 x 교과목 평점)의 합계 &amp; 수강신청 총 학점 수 ---&gt; 과목(코스)</li>
</ol>
</blockquote>
<br>


<p><span style="background-color:#FDCEDF"><strong>Course.java</strong></span></p>
<ul>
<li><span style="background-color:#F8E8EE"><strong>Field</strong></span><ul>
<li><strong>String subject</strong> // 과목명</li>
<li><strong>int credit</strong> // 학점</li>
<li><strong>String grade</strong> // 성적 (A+, A, B+, .... )</li>
</ul>
</li>
<li><span style="background-color:#F8E8EE"><strong>Method</strong></span><ul>
<li><strong>int getCredit()</strong> // 학점 반환</li>
<li><strong>double getGradeToNumber()</strong> // 문자인 성적을 double로 변환하여 반환</li>
</ul>
</li>
</ul>
<pre><code>public class Course {
    private final String subject; 
    private final int credit; 
    private final String grade; 

    public Course(String subject, int credit, String grade) {
        this.subject = subject;
        this.credit = credit;
        this.grade = grade;
    }

    public int getCredit() {
        return credit;
    }

    public double getGradeToNumber() {
        double gradeInt = 0;
        switch (this.grade) {
            case &quot;A+&quot;:
                gradeInt = 4.5;
                break;
            case &quot;A&quot;:
                gradeInt = 4.0;
                break;
            case &quot;B+&quot;:
                gradeInt = 3.5;
                break;
            case &quot;B&quot;:
                gradeInt = 3.0;
                break;
            case &quot;C+&quot;:
                gradeInt = 2.5;
                break;
            case &quot;C&quot;:
                gradeInt = 2.0;
                break;
            case &quot;D+&quot;:
                gradeInt = 1.5;
                break;
            case &quot;D&quot;:
                gradeInt = 1.0;
                break;
            case &quot;F&quot;:
                gradeInt = 0.0;
                break;
        }
        return gradeInt;
    }
}</code></pre><br>

<p><span style="background-color:#FDCEDF"><strong>CourseTest.java</strong></span></p>
<pre><code>public class CourseTest {
    @DisplayName(&quot;과목(코스)를 생성한다.&quot;)
    @Test
    void createTest() {
        assertThatCode(()-&gt; new Course(&quot;OOP&quot;, 3, &quot;A&quot;)).doesNotThrowAnyException();
    }
}</code></pre><br>


<p><span style="background-color:#FDCEDF"><strong>GradeCalculator.java</strong></span></p>
<ul>
<li><span style="background-color:#F8E8EE"><strong>Field</strong></span><ul>
<li><strong>List&lt; Course &gt; coures</strong> // 이수 과목명 List</li>
</ul>
</li>
<li><span style="background-color:#F8E8EE"><strong>Method</strong></span><ul>
<li><strong>double calculateGrade()</strong> // 이수 과목들의 학점 구하기</li>
</ul>
</li>
</ul>
<pre><code>public class GradeCalculator {
    private final List&lt;Course&gt; coures;
    public GradeCalculator(List&lt;Course&gt; courses) {
        this.coures = courses;
    }

    // 전달 받은 이수 과목들의 학점 구하기
    public double calculateGrade() {
        // (학점 수 x 교과목 평점)의 합계
        double multiplideCreditAndCourseGrade = 0;
        for( Course course : coures){
            multiplideCreditAndCourseGrade += course.getCredit() * course.getGradeToNumber();
        }

        // 수강신청 총학점 수
        int totalCompletedCredit = coures.stream()
                .mapToInt(Course::getCredit)
                .sum();
        return multiplideCreditAndCourseGrade / totalCompletedCredit;
    }
}</code></pre><p><span style="background-color:#FDCEDF"><strong>GradeCalculatorTest.java</strong></span></p>
<ul>
<li><p><strong>GradeCalculator gradeCalculator = new GradeCalculator(courses);</strong> </p>
<ul>
<li>이수한 과목 전달</li>
</ul>
</li>
<li><p><strong>double gradeResult = gradeCalculator.calculateGrade();</strong> </p>
<ul>
<li>이수한 과목들의 학점 계산</li>
</ul>
</li>
<li><p><strong>assertThat(gradeResult).isEqualTo(4.5);</strong></p>
<ul>
<li><p>이수한 과목들의 학점이 4.5가 맞는지 확인</p>
<pre><code>public class GradeCalculatorTest {
@DisplayName(&quot;평균 학점을 계산한다.&quot;)
@Test
void calculateGradeTest() {
    List&lt;Course&gt; courses = List.of(new Course(&quot;OOP&quot;, 3, &quot;A+&quot;),
            new Course(&quot;자료구조&quot;, 3, &quot;A+&quot;));

    GradeCalculator gradeCalculator = new GradeCalculator(courses); // 이수한 과목 전달
    double gradeResult = gradeCalculator.calculateGrade(); // 이수한 과목의 성적 계산
    assertThat(gradeResult).isEqualTo(4.5);
}
}</code></pre></li>
</ul>
</li>
</ul>
<br>

<h3 id="span-stylebackground-colorf9f5f6-⛔-but-문제-발생-⛔span"><span style="background-color:#F9F5F6"> ⛔ BUT 문제 발생 ⛔</span></h3>
<ul>
<li><p>Course는 <strong>학점</strong>과 <strong>성적</strong>이 변수로 선언</p>
<pre><code>public class Course {
  private final String subject; 
  private final int credit; 
  private final String grade; 
  ...
}</code></pre></li>
<li><p>(학점 수 x 교과목 평점)의 합계를 course가 계산하는 것이 아니라 <strong>getter</strong>로 가져와서 <strong>GradeCalculator</strong>에서 수행</p>
<pre><code>public class GradeCalculator {
  ...
  public double calculateGrade() {
      // (학점 수 x 교과목 평점)의 합계
      double multiplideCreditAndCourseGrade = 0;
      for( Course course : coures){
          multiplideCreditAndCourseGrade += course.getCredit() * course.getGradeToNumber();
      }

      // 수강신청 총학점 수
      int totalCompletedCredit = coures.stream()
              .mapToInt(Course::getCredit)
              .sum();
      return multiplideCreditAndCourseGrade / totalCompletedCredit;
  }
}</code></pre></li>
</ul>
<h4 id="📣-학점-수-x-교과목-평점의-합계가-여러-군데에서-사용-시에는">📣 (학점 수 x 교과목 평점)의 합계가 여러 군데에서 사용 시에는?</h4>
<ul>
<li>해당 로직이 변경되면 여러 군데 모두 수정 필요</li>
<li><blockquote>
<p><span style="background-color:#FDCEDF"> <strong>응집도가 약하다!</strong></span></p>
</blockquote>
<pre><code>       // (학점 수 x 교과목 평점)의 합계
       double multiplideCreditAndCourseGrade = 0;
       for( Course course : coures){
           multiplideCreditAndCourseGrade += course.getCredit() * course.getGradeToNumber();
       }</code></pre></li>
</ul>
<h3 id="span-stylebackground-colorfdcedf💡-해결-방법span"><span style="background-color:#FDCEDF">💡 해결 방법</span></h3>
<ul>
<li>getter 대신 (학점 수 x 교과목 평점)의 합계를 <strong>Course에서 학점 계산 수행</strong></li>
<li>해당 객체에게 작업 위임!</li>
<li>Course.java<pre><code>  public double multiplyCreditAndGrade() {
      return credit * getGradeToNumber();
  }</code></pre></li>
<li>GradeCalculator.java<pre><code>public double calculateGrade() {
      double multiplideCreditAndCourseGrade = 0;
      for( Course course : coures){
          multiplideCreditAndCourseGrade += course.multiplyCreditAndGrade();
      }
      ...
}</code></pre><ul>
<li>기존 getter 방식에는 사용하는 곳곳마다 찾아가서 수정 요구 </li>
<li>정보를 가진 객체에게 메세지를 전달하여 해당 객체에서 수행한다면 해당 한 부분만 수정해주면 된다!</li>
<li><blockquote>
<p><strong>응집도가 높으므로 변화가 있을때 한군데만 수정하면 ok</strong></p>
</blockquote>
</li>
</ul>
</li>
</ul>
<h3 id="span-stylebackground-colorfdcedf📌-정리span"><span style="background-color:#FDCEDF">📌 정리</span></h3>
<ul>
<li>getter로 가져와서 정보를 처리하는 방법 대신 해당 데이터를 가진 객체에게 메시지를 던져서(메소드) 작업을 시켜주는 것이 변화에 유연하다!</li>
</ul>
<h3 id="span-stylebackground-colorfdcedf📂-일급-컬렉션-사용span"><span style="background-color:#FDCEDF">📂 일급 컬렉션 사용</span></h3>
<ul>
<li><p>아직까지도 이 부분이 GradeCalculator에 존재!</p>
<pre><code>public double calculateGrade() {
      // (학점 수 x 교과목 평점)의 합계
      double multiplideCreditAndCourseGrade = 0;
      for( Course course : coures){
          multiplideCreditAndCourseGrade += course.multiplyCreditAndGrade();
      }
     ...
}</code></pre></li>
<li><p>Courses.java</p>
<pre><code>public class Courses {
  private final List&lt;Course&gt; courses;

  public Courses(List&lt;Course&gt; courses) {
      this.courses = courses;
  }

  public double multipyCreditAndCourseGrade() {
      return courses.stream()
              .mapToDouble(Course::multiplyCreditAndGrade)
              .sum();
  }

  public int calculateTotalCompletedCredit() {
      return courses.stream()
              .mapToInt(Course::getCredit)
              .sum();
  }
}</code></pre></li>
<li><p>GradeCalculator.java</p>
<ul>
<li><p><strong>private final List<Course> courses;</strong> // Courses로 이동</p>
</li>
<li><p><strong>private final Courses courses;</strong> // Field에 Courses 객체 선언</p>
<pre><code>public class GradeCalculator {
private final Courses courses;

public GradeCalculator(List&lt;Course&gt; courses) {
    this.courses = new Courses(courses);
}

//전달 받은 이수 과목들의 (학점 수 x 교과목 평점)의 합계 구하기
public double calculateGrade() {
    // (학점 수 x 교과목 평점)의 합계
    double totalMultipliedCreditAndCourseGrade = courses.multipyCreditAndCourseGrade();

    // 수강신청 총학점 수
    int totalCompletedCredit = courses.calculateTotalCompletedCredit();

    return totalMultipliedCreditAndCourseGrade / totalCompletedCredit;
}
}</code></pre></li>
<li><p>GradeCalculator에 있던 정보가 <strong>multipyCreditAndCourseGrade()</strong>이라는 Courses로 이동</p>
</li>
</ul>
</li>
</ul>
<h4 id="span-stylebackground-colorfdcedf일급-컬렉션이란span"><span style="background-color:#FDCEDF">일급 컬렉션이란?</span></h4>
<ul>
<li>Course들을 여러개 가진 정보만을 인스턴스로 가지는 클래스 </li>
<li>해당 정보만 가진 / 여러 개의 코스 정보만을 가진 클래스 (ex 리스트 형태)</li>
<li>이 정보를 가지고 처리할 수 있는 책임들이 해당 일급 컬렉션 밑으로 모두 이동!</li>
<li>수정이 들어오면 해당 메소드만 수정!</li>
</ul>
<h4 id="span-stylebackground-colorf8e8ee핵심-포인트span"><span style="background-color:#F8E8EE">핵심 포인트</span></h4>
<ol>
<li><p>이수한 과목을 전달하여 평균학점 계산 요청 ---&gt; 학점 계산기</p>
<ul>
<li>이수한 과목을 전달하여 평균학점 계산 요청<pre><code>GradeCalculator gradeCalculator = new GradeCalculator(courses); // 이수한 과목 전달
double gradeResult = gradeCalculator.calculateGrade(); // 이수한 과목의 성적 계산</code></pre></li>
</ul>
</li>
<li><p>학점 계산기 ---&gt; (학점 수 x 교과목 평점)의 합계 ---&gt; 과목(코스)</p>
<ul>
<li><p>학점 계산기 ---&gt; (학점 수 x 교과목 평점)의 합계 ---&gt; 과목(코스)   </p>
<pre><code>public double calculateGrade() {
   // (학점 수 x 교과목 평점)의 합계
   double totalMultipliedCreditAndCourseGrade = courses.multipyCreditAndCourseGrade();

   // 수강신청 총학점 수
   int totalCompletedCredit = courses.calculateTotalCompletedCredit();

   return totalMultipliedCreditAndCourseGrade / totalCompletedCredit;
}</code></pre></li>
<li><p>학점 수 교과목 평균의 합계를 구하기 위해 일급 컬렉션에게 메소드 전달하고 값을 받아온다!</p>
</li>
<li><p>과목 (코스) 일급 컬렉션에게 작업을 위임해서 값을 받아옴</p>
</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[테스트 코드 실습 (사칙연산 계산기)]]></title>
            <link>https://velog.io/@rosie_98/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%8B%A4%EC%8A%B5-%EC%82%AC%EC%B9%99%EC%97%B0%EC%82%B0-%EA%B3%84%EC%82%B0%EA%B8%B0</link>
            <guid>https://velog.io/@rosie_98/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%8B%A4%EC%8A%B5-%EC%82%AC%EC%B9%99%EC%97%B0%EC%82%B0-%EA%B3%84%EC%82%B0%EA%B8%B0</guid>
            <pubDate>Thu, 18 May 2023 07:06:31 GMT</pubDate>
            <description><![CDATA[<h3 id="span-stylebackground-colore3f4f4📝-요구사항span"><span style="background-color:#E3F4F4">📝 요구사항</span></h3>
<ul>
<li>간단한 사칙연산</li>
<li>양수로만 계산 가능</li>
<li>나눗셈에서 0으로 나누는 경우 IllegalArgument 예외 발생</li>
</ul>
<h3 id="span-stylebackground-colore3f4f4-📂-코드-span"><span style="background-color:#E3F4F4"> 📂 코드 </span></h3>
<p><span style="background-color:#D2E9E9"><strong>ArithmeticOperator : enum</strong></span></p>
<ul>
<li><p>사칙 연산 수행 enum</p>
</li>
<li><p>코드</p>
<pre><code>public enum ArithmeticOperator {
// enum 선언
// ADDITION(&quot;+&quot;), SUBTRACTION(&quot;-&quot;), MULTIPLICATION(&quot;*&quot;), DIVISION(&quot;/&quot;);

// 추상 메소드 구현
ADDITION(&quot;+&quot;) {
    @Override
    public int calculate(final int operand1, final int operand2) {
    return operand1 + operand2;
    }
},
SUBTRACTION(&quot;-&quot;) {
    @Override
    public int calculate(final int operand1, final int operand2) {
        return operand1 - operand2;
    }
},
MULTIPLICATION(&quot;*&quot;) {
    @Override
    public int calculate(final int operand1, final int operand2) {
        return operand1 * operand2;
    }
},
DIVISION(&quot;/&quot;) {
    @Override
    public int calculate(final int operand1, final int operand2) {
        if (operand2 == 0) {
            throw new IllegalArgumentException(&quot;0으로 나눌 수 없습니다.&quot;);
        }
        return operand1 / operand2;
    }
};    

// 각각의 산술 연산자를 operator로 명령하겠다는 코드.
private final String operator;

// ArithmeticOperator 생성자
ArithmeticOperator(String operator) {
    this.operator = operator;
}

// 추상 메소드
public abstract int arithmeticCalculate(final int operand1, final int operand2);

public static int calculate(int operand1, String operator, int operand2) {
    // 해당 연산자에 일치하는 enum 값을 가져온다. 
    ArithmeticOperator arithmeticOperator = Arrays.stream(ArithmeticOperator.values())
            .filter(v -&gt; v.operator.equals(operator))
            .findFirst()
            .orElseThrow(() -&gt; new IllegalArgumentException(&quot;올바른 사칙연산이 아닙니다.&quot;));

    // enum 값에 해당하는 enum의 메소드 실행
    return arithmeticOperator.calculate(operand1, operand2);
}
}</code></pre></li>
</ul>
<br>

<p><span style="background-color:#D2E9E9"><strong>Calculator : class</strong></span></p>
<ul>
<li>직접 사칙 연산을 수행하는 것이 아닌 <strong>ArithmeticOperator</strong>에게 사칙 연산 작업을 요청</li>
<li>코드<pre><code>public class Calculator {
  public static int calculate(int operand1, String operator, int operand2) {
      return ArithmeticOperators.calculate(operand1, operator, operand2);
}</code></pre><Br>

</li>
</ul>
<p><span style="background-color:#D2E9E9"><strong>CalculatorTest : class</strong></span></p>
<ul>
<li><p>Test class</p>
</li>
<li><p>코드</p>
<ul>
<li><p><strong>@MethodSource</strong>를 통해 하나의 테스트 코드로 4가지 연산을 수행 가능하다.</p>
</li>
<li><p>formulaAndResult()은 &quot;<strong>static</strong>&quot;이어야 한다.</p>
<pre><code>public class CalculatorTest {
@DisplayName(&quot;덧셈 연산을 정상적으로 수행한다.&quot;)
@ParameterizedTest
@MethodSource(&quot;formulaAndResult&quot;)
void calculateTest(int operand1, String operator, int operand2, int result) {
    int calculateResult = Calculator.calculate(operand1, operator, operand2);
    assertThat(calculateResult).isEqualTo(result);
}

// static이어야 한다!
private static Stream&lt;Arguments&gt; formulaAndResult(){
    return Stream.of(
            arguments(1, &quot;+&quot;, 2, 3),
            arguments(1, &quot;-&quot;, 2, -1),
            arguments(4, &quot;*&quot;, 2, 8),
            arguments(4, &quot;/&quot;, 2, 2)
    );
}
}</code></pre></li>
</ul>
</li>
</ul>
<br>

<h3 id="span-stylebackground-colore3f4f4-🔗-흐름-구조span"><span style="background-color:#E3F4F4"> 🔗 흐름 구조</span></h3>
<p><img src="https://velog.velcdn.com/images/rosie_98/post/25db8231-4e48-4739-a97e-807e193db14c/image.png" alt=""></p>
<ol>
<li>Test code에서 Calculator에게 작업을 위임</li>
<li>Calculator은 enum인 ArithmeticOperator에게 해당 연산 작업을 다시 한번 작업 위임</li>
<li>enum ArithmeticOperator에게 연산 작업을 수행 및 결과값 전달</li>
</ol>
<p><strong>-&gt; 객체들이 협력을 해 결과값을 리턴해주는 구조</strong></p>
<p><span style="background-color:#D2E9E9"><strong>PositiveNumber : class</strong></span></p>
<ul>
<li>피연산자의 양음수 판단 class</li>
</ul>
<p><span style="background-color:#D2E9E9"><strong>NewArithmeticOperator : interface</strong></span></p>
<ul>
<li>인터페이스<pre><code>public interface NewArithmeticOperator {
  boolean supports(String operator);
  int calculate(int operand1, int operand2);
}</code></pre></li>
</ul>
<p><span style="background-color:#D2E9E9"><strong>NewArithmeticOperator 구현 class</strong></span></p>
<ol>
<li>AdditionOperator</li>
</ol>
<ul>
<li><p>덧셈 연산 class</p>
</li>
<li><p>코드</p>
<pre><code>public class AdditionOperator implements NewArithmeticOperator {
  // operator와 해당 연산자가 같는지 비교값을 boolean 타입으로 반환
  @Override
  public boolean supports(String operator) {
      return &quot;+&quot;.equals(operator);
  }

    // 만약 같다면, 피연산자의 사칙 연산 값을 반환
  @Override
  public int calculate(int operand1, int operand2) {
      return operand1 + operand2;
  }
}</code></pre></li>
</ul>
<ol start="2">
<li>SubstractOperator</li>
</ol>
<ul>
<li>뺄셈 연산 class</li>
</ul>
<ol start="3">
<li>DivisionOperator</li>
</ol>
<ul>
<li>나누셈 연산 class</li>
</ul>
<ol start="4">
<li>MultiplicationOperator</li>
</ol>
<ul>
<li>곱셈 연산 class</li>
</ul>
<p>  &lt;수정 중&gt;</p>
<p>  인터페이스를 가지는 
  각각의 구현체들을 상위 인터페이스인 __를 통해서 받는다.
  operator에 해당하는 실제 구현체를 필터링해서 
  선택받은 오퍼레이터에 해당 calculate() 호출
  만약 찾기 못하면 예외발생</p>
<pre><code>4개의 구현체를 리스트로 받는다.</code></pre><p>  오퍼레이터에 맞는 구현체를 찾은 다음
  구현체의 calculate() 작업 위임
  int로 받기 위해 map</p>
<p>IF 0으로 나눠야 하는 경우에는?</p>
<pre><code>    @DisplayName(&quot;나눗셈에서 0으로 나누는 경우 IllegalArgument  예외를 발생시킨다.&quot;)
    @Test
    void CalculateExceptionTest() {
        assertThatCode(() -&gt; Calculator.calculate(10,&quot;/&quot;,0))
                .isInstanceOf(IllegalArgumentException.class);
    }</code></pre><p>BUT  IllegalArgumentException이 발생하지 않는다.</p>
<pre><code>@Override
    public int calculate(int operand1, int operand2) {
        if (operand2 == 0) {
            throw new IllegalArgumentException(&quot;0으로 나눌 수 없습니다.&quot;);
        }
        return operand1 / operand2;
    }</code></pre><p>양수로만 계산 가능하다</p>
<pre><code>public class PositiveNumber {
    private  final int value;

    public PositiveNumber(int value) {
        this.value = value;
    }

    private void validate(int value){
        if(isNegativeNumber(value)){
            throw new IllegalArgumentException(&quot;0 또는 음수를 전달할 수 없습니다.&quot;);
        }
    }

    private boolean isNegativeNumber(int value){
        return value &lt;= 0;
    }

}</code></pre><ul>
<li>0 또는 음수면 IllegalArgumentException 예외 발생 </li>
<li>양수면 객체 생성 -&gt; 양수라는 것을 보장!</li>
</ul>
<pre><code>public class Calculator {
    public static int calculate(int num1, String operator, int num2) {...}
}</code></pre><pre><code>public class Calculator {
     public static int calculate(PositiveNumber num1, String operator, PositiveNumber num2) {...}
}</code></pre><p>  나머지 인자도 int 타입에서 PositiveNumber으로 변경</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[테스트 코드 실습 (비밀번호 유효성 검증기)]]></title>
            <link>https://velog.io/@rosie_98/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%8B%A4%EC%8A%B5-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%A6%9D%EA%B8%B0</link>
            <guid>https://velog.io/@rosie_98/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%8B%A4%EC%8A%B5-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EC%9C%A0%ED%9A%A8%EC%84%B1-%EA%B2%80%EC%A6%9D%EA%B8%B0</guid>
            <pubDate>Thu, 18 May 2023 07:06:23 GMT</pubDate>
            <description><![CDATA[<h3 id="span-stylebackground-colorc4dfdf🔃-tdd-circle-of-lifespan"><span style="background-color:#C4DFDF">🔃 TDD circle of life</span></h3>
<ol>
<li>Test fails</li>
<li>Test passes</li>
<li>Refactor</li>
</ol>
<h3 id="span-stylebackground-colorc4dfdf🔠용어-정의span"><span style="background-color:#C4DFDF">🔠용어 정의</span></h3>
<ul>
<li><strong>main 디렉토리</strong> ➞ 프로덕션 코드</li>
<li><strong>test 디렉토리</strong> ➞ 테스트 코드</li>
</ul>
<h3 id="span-stylebackground-colorc4dfdf🔧-실습-전-환경-설정span"><span style="background-color:#C4DFDF">🔧 실습 전 환경 설정</span></h3>
<ul>
<li><span style="background-color:#F8F6F4"><strong>AssertJ</strong></span> dependency 추가<ul>
<li>테스트 코드 가독성을 높여주는 자바 라이브러리<pre><code>testImplementation &#39;org.assertj:assertj-core:3.23.1&#39;</code></pre></li>
</ul>
</li>
<li>main과 test 디렉토리 구조를 맞춰주는 것이 좋으므로, 
test의 하위 디렉토리인 java에 &#39;<strong>org.example</strong>&#39; (main의 패키지명) 패키지 생성</li>
</ul>
<h3 id="span-stylebackground-colorc4dfdf💻-실습-코드span"><span style="background-color:#C4DFDF">💻 실습 코드</span></h3>
<p><span style="background-color:#F8F6F4"><strong>@DisplayName(&quot;&quot;)</strong></span></p>
<ul>
<li>해당 테스트 코드의 의도를 표현하는 annotation</li>
<li>예시)<pre><code>@DisplayName(&quot;비밀번호 최소 8자 이상 12자 이하이면 예외가 발생하지 않는다.&quot;)
  @Test
  void validatorPasswordTest() {  ...  }</code></pre></li>
</ul>
<br>

<p><span style="background-color:#F8F6F4"><strong>@ParameterizedTest</strong></span></p>
<ul>
<li>dependency 추가 필요<pre><code>testImplementation &#39;org.junit.jupiter:junit-jupiter-params:5.8.2&#39;</code></pre></li>
<li><a href="https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/">https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/</a></li>
<li>예시)<pre><code>@ParameterizedTest
@ValueSource(strings = {&quot;aabbcce&quot;, &quot;aabbccddeeffg&quot;})
void test(String str) { ... }</code></pre></li>
</ul>
<br>

<h3 id="span-stylebackground-colorc4dfdf💻-더-낮은-결합도를-위한-테스트-코드-작성하기span"><span style="background-color:#C4DFDF">💻 더 낮은 결합도를 위한 테스트 코드 작성하기</span></h3>
<p><span style="background-color:#F8F6F4">🔧 <strong>환경 설정</strong></span> </p>
<ul>
<li><strong>passay</strong> 의존성 추가<ul>
<li>패스워드를 생성해주는 자바 라이브러리<pre><code>implementation &#39;org.passay:passay:1.6.1&#39;</code></pre></li>
</ul>
</li>
</ul>
<p><span style="background-color:#F8F6F4">💻 <strong>코드 설명</strong></span></p>
<ul>
<li><p><strong>RandomPasswordGenerator Class</strong></p>
<ul>
<li>0부터 13자리의 패스워드를 랜덤하게 생성하는 class</li>
</ul>
</li>
<li><p><strong>User class</strong></p>
<ul>
<li><strong>initPassword()</strong> : 패스워드 초기화<pre><code>public void initPassword() {
    RandomPasswordGenerator randomPasswordGenerator = new RandomPasswordGenerator();
    String randomPassword = randomPasswordGenerator.generatePassword();
    if (randomPassword.length() &gt;= 8 &amp; randomPassword.length() &lt;= 12) {
        this.password = randomPassword;
    }
}</code></pre></li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>UserTest class</strong></p>
<pre><code> @DisplayName(&quot;패스워드를 초기화한다.&quot;)
  @Test
  void passwordTest() {
      // given
      User user = new User();

      // when
      user.initPassword();

      // then
      assertThat(user.getPassword()).isNotNull();
  }</code></pre></li>
</ul>
<p>📌 테스트 케이스 실행 결과, 어떨 때는 성공이고, 어떨 때는 실패!</p>
<h4 id="✖-why">✖ WHY?</h4>
<h4 id="user-class">User class</h4>
<pre><code>RandomPasswordGenerator randomPasswordGenerator = new RandomPasswordGenerator();</code></pre><ul>
<li>패스워드를 몇 글자로 생성할지 모르기 때문에 Test 코드 실행 시, 오류가 없거나 발생!</li>
</ul>
<h4 id="✔-how">✔ HOW?</h4>
<ol>
<li><p><span style="background-color:#F8F6F4"><strong>interface</strong></span> 생성 (PasswordGeneratePolicy Interface)</p>
<pre><code>public interface PasswordGeneratePolicy {
 String generatePassword();
}</code></pre></li>
<li><p>RandomPasswordGenerator가 PasswordGeneratePolicy를 구현</p>
<pre><code>public class RandomPasswordGenerator implements PasswordGeneratePolicy  {...}</code></pre></li>
</ol>
<ol start="3">
<li><p>컨트롤할 수 없었던 코드를 <span style="background-color:#F8F6F4"><strong>외부로부터 주입받기</strong></span> 생성</p>
<ul>
<li><p>컨트롤할 수 없었던 코드</p>
<pre><code>RandomPasswordGenerator randomPasswordGenerator = new RandomPasswordGenerator();</code></pre></li>
<li><p>User Class</p>
<pre><code>public void initPassword(PasswordGeneratePolicy passwordGeneratePolicy ) {
   String randomPassword = passwordGeneratePolicy.generatePassword();
   ...}</code></pre></li>
<li><p>테스트 코드</p>
<pre><code>void passwordTest() {
   // given
   User user = new User();

   // when
   user.initPassword(new CorrectFixedPasswordGenerator());

   // then
   assertThat(user.getPassword()).isNotNull();
}
</code></pre></li>
</ul>
<pre><code></code></pre><p>void passwordTest2() {</p>
<pre><code> // given
 User user = new User();

 // when
 user.initPassword(new WrongFixedPasswordGenerator());

 // then
 assertThat(user.getPassword()).isNull();</code></pre><p> }</p>
<pre><code></code></pre></li>
</ol>
<h3 id="mark-stylebackground-colorc4dfdf📖-정리mark"><mark style="background-color:#C4DFDF">📖 정리</mark></h3>
<ul>
<li>기존엔 내부에서 RandomPassword를 받아, RandomPasswordGenerator를 통해 패스워드 생성하고, 조건(8글자 이상 12글자 이하)에 맞춰 패스워드를 초기화</li>
<li>하지만 테스트를 돌릴 때마다 실패, 성공 반복...!</li>
<li>이를 컨트롤하기 위해서 PasswordGeneratePolicy 인터페이스 정의</li>
<li>PasswordGeneratePolicy를 구현한 CorrectFixedPasswordGenerator(8글자 이상 12글자 이하의 패스워드 생성 및 반환), WrongFixedPasswordGenerator(8글자 미만 12글자 초과의 패스워드 생성 및 반환)를 통해서 항상 통과 / 실패하는 테스트 생성!</li>
</ul>
<Br>




<pre><code>user.initPassword(new CorrectFixedPasswordGenerator());</code></pre><ul>
<li>항상 통과!</li>
</ul>
<pre><code>user.initPassword(new WrongFixedPasswordGenerator());</code></pre><ul>
<li>항상 실패!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[도커 및 도커 컴포즈]]></title>
            <link>https://velog.io/@rosie_98/%EB%8F%84%EC%BB%A4-%EB%B0%8F-%EB%8F%84%EC%BB%A4-%EC%BB%B4%ED%8F%AC%EC%A6%88</link>
            <guid>https://velog.io/@rosie_98/%EB%8F%84%EC%BB%A4-%EB%B0%8F-%EB%8F%84%EC%BB%A4-%EC%BB%B4%ED%8F%AC%EC%A6%88</guid>
            <pubDate>Thu, 18 May 2023 07:06:11 GMT</pubDate>
            <description><![CDATA[<h3 id="📌-도커docker">📌 도커(Docker)?</h3>
<ul>
<li>컨테이너 기반의 가상화 플랫폼</li>
</ul>
<h3 id="📌-컨테니어-기반의-가상화-vs-하이퍼바이저-기반의-가상화os-가상화">📌 컨테니어 기반의 가상화 VS 하이퍼바이저 기반의 가상화(OS 가상화)</h3>
<p><img src="https://velog.velcdn.com/images/rosie_98/post/fe559064-e753-4443-a521-4d976815d788/image.png" alt=""></p>
<h4 id="하이퍼바이저-기반의-가상화os-가상화">하이퍼바이저 기반의 가상화(OS 가상화)</h4>
<ul>
<li>격리된 환경에서 또 다른 하나의 서버를 실행하는 기술</li>
<li>Guest OS 가상 서버, Host는 물리 서버라 생각하면 이해하기 쉽다. </li>
<li>Guest Os에서 실행되는 애플리케이션이 host 자원을 사용하기 위해서는 반드시 Guest OS를 거쳐야 한다. <ul>
<li>속도가 느릴 수 있다...</li>
</ul>
</li>
<li><strong>Hyervisor</strong> <ul>
<li>서버 가상화 기술 </li>
<li>Host 서버에 설치 </li>
<li>Host와 Guest 서버를 나누는 역할 </li>
<li>각각의 Guest는 하이퍼바이저에 의해 관리 및 시스템 자원 할당</li>
</ul>
</li>
</ul>
<h4 id="컨테니어-기반의-가상화">컨테니어 기반의 가상화</h4>
<ul>
<li>격리된 환경에서 프로세스를 실행하는 기술</li>
<li>애플리케이션은 도커 엔진을 통해 Host 자원을 사용할 수 있다.</li>
<li>구조적으로 Guest Os가 없어 용량이 가볍다.</li>
</ul>
<h3 id="📌-도커-허브">📌 도커 허브?</h3>
<ul>
<li>Git Hub와 비슷한 개념</li>
</ul>
<h3 id="📌-도커-컴포즈">📌 도커 컴포즈?</h3>
<ul>
<li>다중 컨테이너를 정의하고 실행하기 위한 도구 </li>
<li>여러 개의 프로세스를 하나의 파일로 정의하고 동시에 실행하기 위한 도구</li>
<li>YAML 파일을 사용하여 다중 컨테이너를 구성함</li>
</ul>
<h3 id="📌-도커-설치-완료-명령어">📌 도커 설치 완료 명령어</h3>
<pre><code>docker -v</code></pre><h3 id="📌-도커-허브에서-이미지-다운로드-mysql">📌 도커 허브에서 이미지 다운로드 (MYSQL)</h3>
<pre><code>docker pull mysql:{version}</code></pre><h3 id="📌-도커-컨테이너-생성-및-실행-mysql">📌 도커 컨테이너 생성 및 실행 (MYSQL)</h3>
<pre><code>docker run --name 도커 컨테이너 이름 -e MYSQL_ROOT_PASSWORD=&lt;password&gt; -d -p 3306:3306 mysql:{version}</code></pre><blockquote>
<p>docker run</p>
</blockquote>
<ul>
<li>도커 실행 명령어</li>
</ul>
<blockquote>
<p>MYSQL_ROOT_PASSWORD</p>
</blockquote>
<ul>
<li>패스워드 설정</li>
</ul>
<blockquote>
<p>3306:3306 </p>
</blockquote>
<ul>
<li>port 지정</li>
</ul>
<h3 id="📌-현재-실행-중인-도커-컨테이너-목록-출력">📌 현재 실행 중인 도커 컨테이너 목록 출력</h3>
<pre><code>docker ps -a</code></pre><h3 id="📌-도커-컨데이너-접속-mysql">📌 도커 컨데이너 접속 (MYSQL)</h3>
<pre><code>docker exec -it {도커 컨데이너 이름} bash</code></pre><h3 id="📌-mysql-접속">📌 MYSQL 접속</h3>
<pre><code>mysql -u root -p</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[IntelliJ] 자주 쓰는 단축키 모음 ]]></title>
            <link>https://velog.io/@rosie_98/IntelliJ-IntelliJ-%EB%8B%A8%EC%B6%95%ED%82%A4</link>
            <guid>https://velog.io/@rosie_98/IntelliJ-IntelliJ-%EB%8B%A8%EC%B6%95%ED%82%A4</guid>
            <pubDate>Thu, 18 May 2023 07:03:51 GMT</pubDate>
            <description><![CDATA[<table>
<thead>
<tr>
<th align="left">단축키</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td align="left">F2</td>
<td>오류로 이동 (빨간 색 줄로 이동)</td>
</tr>
<tr>
<td align="left">Alt + Enter</td>
<td></td>
</tr>
<tr>
<td align="left">ctrl + Alt + v</td>
<td>지역 변수로 추출</td>
</tr>
<tr>
<td align="left">ctrl + Alt + c</td>
<td>변수로 추출</td>
</tr>
<tr>
<td align="left">ctrl + shift + enter</td>
<td>문장 완성</td>
</tr>
<tr>
<td align="left">ctrl + alt + v</td>
<td>리턴값에 맞는 변수 자동 생성</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[IntelliJ] Spring boot 자동 빌드 설정]]></title>
            <link>https://velog.io/@rosie_98/IntelliJ-Spring-boot-%EC%9E%90%EB%8F%99-%EB%B9%8C%EB%93%9C-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@rosie_98/IntelliJ-Spring-boot-%EC%9E%90%EB%8F%99-%EB%B9%8C%EB%93%9C-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Wed, 17 May 2023 08:38:02 GMT</pubDate>
            <description><![CDATA[<ol>
<li><p>Edit Configurations... 클릭
<img src="https://velog.velcdn.com/images/rosie_98/post/b6e83337-3346-4259-a0a0-bc3074dc697f/image.png" alt=""></p>
</li>
<li><p>Modify options 탭 클릭
<img src="https://velog.velcdn.com/images/rosie_98/post/07917eab-a304-4b77-b14c-b1da34a405dc/image.png" alt=""></p>
</li>
<li><p>On &#39;Update&#39; acion -&gt; Update classes and resources 
<img src="https://velog.velcdn.com/images/rosie_98/post/bcd24449-5622-448c-96b0-371bbc82bec2/image.png" alt=""></p>
</li>
<li><p>On frame deactivation -&gt; Update classes and resources 
<img src="https://velog.velcdn.com/images/rosie_98/post/abb3a046-132a-43a9-83ea-922f186bada3/image.png" alt=""></p>
</li>
</ol>
<p>-&gt;  IntelliJ가 아닌 다른 창을 클릭 시 자동 빌드가 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[IntelliJ] IntelliJ와 Sql developer 연결하기 (Oracle Wallet 이용)]]></title>
            <link>https://velog.io/@rosie_98/IntelliJ%EC%99%80-sql-developer-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0-Wallet%EC%9C%BC%EB%A1%9C</link>
            <guid>https://velog.io/@rosie_98/IntelliJ%EC%99%80-sql-developer-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0-Wallet%EC%9C%BC%EB%A1%9C</guid>
            <pubDate>Sun, 14 May 2023 05:57:47 GMT</pubDate>
            <description><![CDATA[<h3 id="📌-span-stylebackground-color-e5f9dbintellij에서-oracle-wallet을-이용하여-sql-developer-db와-연결하기span">📌 <span style='background-color: #E5F9DB'>IntelliJ에서 Oracle Wallet을 이용하여 SQL developer DB와 연결하기</span></h3>
<br>
<span style='background-color: #F6FFDE'>🔧 **참고 사항**</span>
<br>- SQL Developer version : 21c

<p><strong>1. 오른쪽 상단에 database 탭 클릭</strong>
<img src="https://velog.velcdn.com/images/rosie_98/post/e9dc73f0-f911-4cf8-bdda-9757bb83c643/image.png" alt=""></p>
<p><strong>_<span style='background-color: #A0D8B3'><span style='color: #fff'>📣 Database 탭이 안보인다면? </span></span>_</strong>
-&gt;  왼쪽 하단의 버튼 클릭! 
<img src="https://velog.velcdn.com/images/rosie_98/post/5fa42fc1-1b71-4d85-903a-ad94ceaa3f21/image.png" alt=""></p>
<p><strong>2. &quot;+&quot; 버튼 클릭 및 Data Source를 클릭한 후, 사용하고자 하는 DB 선택</strong>
<img src="https://velog.velcdn.com/images/rosie_98/post/ac91691e-e4d0-4ca7-b8aa-8fb97d561a23/image.png" alt=""></p>
<p>*<em>3. Connection type을 <span style='background-color: #E5F9DB'>&quot;URL only&quot;</span>로 변경 *</em>
<img src="https://velog.velcdn.com/images/rosie_98/post/355ff351-a7f9-44cc-a8db-bea92b008144/image.png" alt=""></p>
<p><strong>4. DB의 User과 Password 입력 및 
Url에 
<span style='background-color: #E5F9DB'>jdbc:oracle:thin:@DB이름_(high or medium or low)?TNS_ADMIN=&quot;wallet Location 입력&quot;</span></strong>
<img src="https://velog.velcdn.com/images/rosie_98/post/75f7ebea-74d6-4a02-97a9-06cee939a334/image.png" alt=""></p>
<p>✨<text style='background-color: #F6FFDE'><strong>주의사항</strong>
</text></p>
<ul>
<li>Driver는 기본 Oracle로 설정!
<img src="https://velog.velcdn.com/images/rosie_98/post/f1031770-9e4b-4c64-a6c6-29754ced4a79/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[오라클 SQL DB] SQL 오류: ORA-03001: 현재에는 구현되어 있지 않은 기능입니다]]></title>
            <link>https://velog.io/@rosie_98/%EC%98%A4%EB%9D%BC%ED%81%B4-SQL-DB-SQL-%EC%98%A4%EB%A5%98-ORA-03001-%ED%98%84%EC%9E%AC%EC%97%90%EB%8A%94-%EA%B5%AC%ED%98%84%EB%90%98%EC%96%B4-%EC%9E%88%EC%A7%80-%EC%95%8A%EC%9D%80-%EA%B8%B0%EB%8A%A5%EC%9E%85%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@rosie_98/%EC%98%A4%EB%9D%BC%ED%81%B4-SQL-DB-SQL-%EC%98%A4%EB%A5%98-ORA-03001-%ED%98%84%EC%9E%AC%EC%97%90%EB%8A%94-%EA%B5%AC%ED%98%84%EB%90%98%EC%96%B4-%EC%9E%88%EC%A7%80-%EC%95%8A%EC%9D%80-%EA%B8%B0%EB%8A%A5%EC%9E%85%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Wed, 01 Feb 2023 08:17:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rosie_98/post/3aae01dc-f38f-419d-9bec-684b80a3f056/image.png" alt="">
t1 테이블엔 id란 칼럼 1개가 존재한다.</p>
<h2 id="⛔-문제-발생-⛔">[⛔ 문제 발생 ⛔]</h2>
<pre><code>insert into t1 values 2;</code></pre><p>insert 문을 실행시키니 오류 발생!</p>
<p><mark style='background-color: #ffdce0'><strong>_SQL 오류: ORA-03001: 현재에는 구현되어 있지 않은 기능입니다
03001. 00000 -  &quot;unimplemented feature&quot; _</strong></mark></p>
<h2 id="💡-문제-해결-💡">[💡 문제 해결 💡]</h2>
<p>insert하는 값을 ( )로 묶으니 문제 해결
-&gt; 칼럼이 하나인 테이블에 insert을 할 경우에도 삽입할 값을 ( )로 써주기!!!!</p>
<pre><code>insert into t1 values (2);</code></pre>]]></description>
        </item>
    </channel>
</rss>