레이블이 java인 게시물을 표시합니다. 모든 게시물 표시
레이블이 java인 게시물을 표시합니다. 모든 게시물 표시

2020년 9월 16일 수요일

[인프런] 더 자바 - 코드를 조작하는 다양한 방법 수강후기

 백기선님 4번째 강의이다.

https://www.inflearn.com/course/the-java-code-manipulation#

예전에 구매했던 강의인데, 김영한님 JPA강의 시작 전 빨리 봐야겠다는 생각이 들어서 
빨리 완강해버렸다. 277분이기 때문에 마음만 먹으면 빠르게 완강 가능하다. 
이 강좌는 누군가 공짜로 설명해주지 않는 내용이다. (누가 이렇게 설명 해줄까...?)

강의는 자바 심화 과정으로 '자바는 어떻게 코드, 객체를 조작하는가?' 에 대해 설명한다.
강의목표는 자바 라이브러리와 프레임워크들이 제공하는 편의기능들의 원리에 대해 설명하고자 하는 것 같다.

  • 코드 조작이 어떻게 이루어지는 지 이해하기 위한 JVM 구조 설명
  • java코드를 조작하지 않고 어떻게 코드를 조작할 수 있는 지?
  • 어노테이션들은 어떻게 편의기능을 제공하는 지?

에 대해서 쉽고 전문적으로 예제와 함께 설명해준다.


최근에 자꾸 와닿는 느낀점은 시간에 따른 학습 이해도가 정말 다르다는 것이다. 
예전에 공부했던 내용을 나중에 다시 공부할 때 그동안의 경험이나, 인식(?)으로 학습 내용이 정말 확 와닿고 머리에 딱 들어오는 경우가 있다. 
너무 이해가 안된다고 끙끙 앓지 말고 실전 경험 후 자연스럽게 이해하는 것도 좋은 것 같다.

API를 설계하거나 만들 때 리플렉션, 프록시 부분은 꼭 다시 강의 복습해보자!!

2018년 10월 9일 화요일

JDBC , DBCP, JNDI (수정필요)

JDBC(Java Database Connectivity)
: 데이터베이스에 접근하여 SQL문을 실행하기 위한 자바 라이브러리

>>  자바프로그래밍의 일반적인 데이터 엑세스 제공 
>> 데이터베이스 풀 방식을 사용하지 않고 DB에서 정보를 가져올 때마다 매번 디비 연결을 열고 닫음
>> 효율이 떨어짐 
>> 그렇기 때문에 보통 pool 방식을 사용함. (ex DBCP)

==========================================================

DBCP(Database Connection Pool) 
: 데이터베이스와 연결된 커넥션을 미리 만들어서 저장해두고 있다가 필요할 때 저장된 공간(Pool)에서 가져다 쓰고 반환하는 기법

>> DB커넥션을 어플리케이션 소스 내에서 제어하면서 DB 풀을 가짐
>> 사용자가 요청할 경우 드라이버를 로드하고, 커넥션 객체를 생성해 연결하고 종료하는 비효율적인 작업을 하지 않아도 됨
>> 데이터베이스의 부하를 줄이고 자원을 효율적으로 관리

==========================================================

JNDI(Java Naming and Directory Interface)
: 디렉터리 서비스에서 제공하는 데이터 및 객체를 발견하고 참고하기 위한 자바API
(외부에 있는 객체를 가져오기 위한 기술)

>> DB커넥션을 WAS단(외부)에서 제어하면서 서버에서 하나의 커넥션 풀을 가짐
>> DBCP처럼 어플리케이션 소스단에 설정하느 방식이 아닌 WAS단에 데이터베이스 커넥션 객체를 미리 네이밍함
>> 소스단에 정보를 설정해놓으면 소스 개발자 외에는 정보를 찾기가 힘들다. 하지만 JNDI를 사용하면  WAS단에 저장하기 때문에 파악하기 쉬움..????
>> 서버단에서 어플리케이션 컨테이너는 하나이더라도 내부 어플리케이션 소스는 홈페이지 하나 이상이 될 수있는데(디렉토리 서비스, 서브도메인을 사용하여 서비스하는 경우) 이 경우, DBCP를 사용하면 각 어플리케이션마다 DB Pool이 각자 생성되어 풀이 많아져 효율이 떨어질 수 있음. 
JNDI는 WAS단에서 DB Pool를 하나로 관리하기 때문에 효율이 좋아진다고 함..
(WAS에 스태틱 객체를 생성 후에 쉽게 가져다 쓸 수 있기 때문??)


참고

http://eongeuni.tistory.com/43
http://all-record.tistory.com/104

todo

http://nastyle.tistory.com/15
https://d2.naver.com/helloworld/5102792

2018년 10월 2일 화요일

자바 로그(log) 남기기 - log4j, log4j2, logback, slf4j (간단한 logback 실습)

로그란? (log)

애플리케이션의 상태를 관찰할 수 있도록 애플리케이션이 제공하는 정보 

log4j, logback, log4j2  셋 다 java 로깅 유틸리티이다.

스프링프레임워크에서는  예전에는 commons.logging을 기본으로 사용하였지만, 지금은 slf4j, log4j 를 기본으로 사용?
시간 순서로 보면 Log4j -> Logback -> Log4j2 인듯?
----------------------------------------------------------------------------------------------

Log4j ? (log for java) 

Apache에서 만든 오픈소스 라이브러리로 프로그램을 작성하는 도중에 로그를 남기기 위해 사용되는 자바 기반 로깅 유틸리티

- 구조
Logger - 로깅이 일어나는 부분을 그룹화해, 필요한 그룹의 로그만을 출력하거나, 카테고리에 우선순위를 부여함으로써, 여러가지 출력 방법을 지원함. 실제 로그 긴으을 수행하는 역할을 담당.

Appender - 로그의 출력 위치를 지정. 콘솔, 파일, outputstream, java.io.Writer, Email(STMP), Network 등이 있음.
 - ConsoleAppender : 콘솔에 로그 메세지를 출력한다.
 - FileAppender: 파일에 로그메시지리를 출력한다.
 - RollingFileAppender: 로그의 크기가 지정한 용량 이상이 되면 다른 이름의 파일을 출력한다.
 - DailyRollingFileAppender: 하루를 단위로 로그 메세지를 파일에 출력한다.
 - SMTPAppender: 로그 메세지를 이메일로 보낸다.
 - NTEventLogAppender: 윈도우의 이벤트 로그 시스템에 기록한다.

Layout - 로그의 출력 포맷을 지정.
 - %d : 로그의 기록시간
 - %p : 로깅의 레벨
 - %F : 로깅이 발생한 프로그램의 파일명
 - %M : 로깅이 발생한 메소드의 이름
 - %I : 호출지의 정보
 - %L : 로깅이 발생한 호출지의 라인 수
 - %t : 로깅이 발생한 Thread 명
 - %c : 로깅이 발생한 카테고리
 - %C : 로깅이 발생한 클래스명
 - %m : 로그 메세지
 - %% : % 출력
 - %r : 시작 이후로부터 로깅이 발생한 시점까지의 시간

----------------------------------------------------------------------------------------------

Log4j2 ? 

이 후에 나온 버전으로 성능과 메시지 처리량 및 대기 시간이 향상되었다고 한다.
log4j 는 xml과 properties를 이용해서 설정하지만, log4j2 는 properties는 지원하지 않는다고함.

-특징
 - 자동적인 로깅 구성설정(?) 리로딩
 - 속성 서포트: Log4j2는 시스템의 속성을 불러오고
 - 자바8: 람다식에서 로그 메시지를 래핑하는 API 제공
 - Log4j2에는 쓰레기 값이 거의 없다.
 - LMAX Disruptor를 사용하는 비동기 logger

----------------------------------------------------------------------------------------------

logback ?

log4j 를 토대로 새롭게 만들어진 로깅 라이브러리로 스프링 부트의 기본 로그 객체.
ERROR < WARN < INFO < DEBUG < TRACE
스프링이나 일반적인 자바프로그램의 경우 resources 디렉토리 안에 logback.xml 참조
(logback.groovy -> logback-test.xml -> logback.xml 순서로 찾는다고함..)
스프링 부트는 logback-spring.xml 파일을 참조

-구조
Log4j와 유사한구조

Logger - 실제 로깅을 수행하는 구성요소로 Level 속성을 통해서 출력할 로그의 레벨을 조절할 수있음.

Appender - 로그 메시지가 출력될 대상을 결정하는 요소
 - ConsoleAppender : 콘솔에 로그를 찍는 방법
 - FileAppender : 파일이 로그를 찍는 방법
 - RollingFileAppender: 여러개의 파일을 순회하면서 로그를 찍는 방법
(상당히 다양하게 쓸 수있는 듯.....)
 - SMTPAppender : 로그를 메일에 찍어 보내는 방법
 - DBAppender:  데이터베이스에 로그를 찍는 방법
Socket, SSLSocket 등이 있음

패턴에 사용되는 요소
 - %Logger{length} : Logger name을 축약할 수 있음 {length}는 최대 자리 수
 - %thread : 현재 Thread 이름
 - %-5level : 로그 레벨, -5는 출력의 고정폭 값
 - %msg : 로그 메시지 ( =%message)
 - %n : new line
 - %highlight: 로그레벨에 따른 색을 줄 수 있는 듯 함

 - 나머지 log4j 와 비슷한 듯..


Encoder - Appender에 포함되어 사용자가 지정한 형식으로 표현 될 로그 메시지를 변환

*layout과 encoder의 차이점: 레이아웃은 들어오는 이벤트를 String으로 변환하고 에빈트가 기록될 때 제어할 수 없으며 이벤트를 일관처리로 집계한다. 반면에 encoder는 바이트를 소유하고 있는 appender가 관리하는 outputStream에 쓸 시간과 내용을 완전히 제어할 수 있음. 
FileAppender와 하위 클래스는 encoder를 필요로 하고 더 이상 layout은 사용하지 않는다.



-특징
1. log4j보다 약 10배 정도 빠름. 메모리 효율성 향상
2. 설정 파일을 변경하였을 경우, 서버 재기동 없이 변경 내용이 자동으로 갱신됨.
3. RollingFileAppender로 자동으로 오래된 로그를 지워줌.

----------------------------------------------------------------------------------------------

SLF4J ? (Simple Logging Facade for Java)

SLF4J 는 자바 로깅 유틸리티의 추상체 역할을 함. 인터페이스와 비슷한 역할을 하며, 사용하던 로깅 유틸리티가 변경되더라도 java소스의 변경을 방지해줌.

개발자는 어떤 상황에든 대처하고 확장될 수 있는 느슨하고 유연한 코드를 만들어야 합니다. 따라서 하나의 라이브러리에 너무 종속적이 되버리는 코드는 가급적 작성하지 않는쪽이 좋습니다. 그렇기에 어떤 라이브러리를 쓰든 동일하게 동작하는 코드를 만들어야하고 그것이 slf4j를 써야하는 이유입니다.


만약 log4j 에서 logback  으로 변경할 때 log4j를 import 하던 파일들을
다 logback 으로 바꿔줘야함.

1
2
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;
cs
소스들 마다 박혀있는 log4j를 바꿔줘야함...


하지만 slf4j를 쓴다면 사용하지 않는 dependency만 제거하면 됨.
1
2
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
cs


======================================================

간단 실습

pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
...
    <properties>
...
        <jcloverslf4j.version>1.7.6</jcloverslf4j.version>
        <logback.version>1.1.7</logback.version>
...
    </properties>
...
        <!-- Logback --> 
         <dependency>                                    
                  <groupId>org.slf4j</groupId>                
                  <artifactId>jcl-over-slf4j</artifactId>     
                  <version>${jcloverslf4j.version}</version>  
         </dependency>
         <dependency>
                  <groupId>ch.qos.logback</groupId>
                  <artifactId>logback-classic</artifactId>
                  <version>${logback.version}</version>
         </dependency>
...
cs


src/main/resources 
logback.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <!-- 로그파일 경로  -->
    <property name="LogFileDir" value="/logs/data.log" />
    <!-- CONSOLE appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern> %d{yyyy-MM-dd HH:mm:ss} [%-5p] [%F]%M\(%L\) : %m%n </pattern>
        </encoder>
    </appender>
    <!--  FILE appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LogFileDir}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LogFileDir}.%d{yyyy-MM-dd}</fileNamePattern>
            <maxHistory>30</maxHistory<!-- 보관의 기간 -->
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5p] [%F]%M\(%L\) : %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.springframework" level="info"/>
    <logger name="org.hibernate" level="debug"/>
    <root level="debug">
        <appender-ref ref="CONSOLE"/<!-- Console에 로그를 출력하고자 할 때 사용 -->
        <appender-ref ref="FILE"/<!-- File로 로그를 남기고자 할 때 사용 -->
    </root>
</configuration>
cs

컨트롤러
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Controller
@RequestMapping("/")
public class HomeController {
...
    private static final Logger LOG = LoggerFactory.getLogger(HomeController.class);
...
    @RequestMapping("/")
    public ModelAndView Home(HttpSession session) throws Exception{
        LOG.debug("-------------------WebBoardList_Start--------------------");
  ...
LOG.debug("-------------------WebBoardList_End--------------------");
...
    }
cs


콘솔창



log파일
파일 내부



출처 및 참고 :






2018년 8월 12일 일요일

EJB / bean

엔터프라이즈 자바빈즈

위키백과, 우리 모두의 백과사전.
둘러보기로 가기검색하러 가기
엔터프라이즈 자바빈즈(Enterprise JavaBeans; EJB)는 기업환경의 시스템을 구현하기 위한 서버측 컴포넌트 모델이다. 즉, EJB는 애플리케이션의 업무 로직을 가지고 있는 서버 애플리케이션이다. EJB 사양은 Java EE의 자바 API 중 하나로, 주로 웹 시스템에서 JSP는 화면 로직을 처리하고, EJB는 업무 로직을 처리하는 역할을 한다.

EJB의 종류[편집]

EJB에는 다음 3가지 종류가 있다.
  • 세션 빈 (Session Bean) : DB 연동이 필요 없음
  • 엔티티 빈 (Entity Bean)
    • 데이터베이스의 데이터를 관리하는 객체
    • Insert(삽입), Update(수정), Delete(삭제), Select(조회)
    • DB 관련 쿼리는 자동으로 만들어지고 개발자는 고급 업무 처리에 집중할 수 있음
    • DB가 수정되면 코드 수정 없이 다시 배포(설정 문서 만들어서 복사)
  • 메시지 구동 빈 (Message-driven Bean) : JMS로 빈을 날려줌


EJB 배경, 설명(블로그 참조) 

http://pokey.tistory.com/7
>>>
EJB는 대규모 분산 객체 시스템을 구축하기 위한 기술 또는 자바로 서버 측 비즈니스 로직을 작성하기 위한 Enterprise 환경에서의 자바 표준이라고 보시면 됩니다. 흔히 프리젠테이션 로직이라고 하는 것이 화면에 보여지게 되는 정보의 타입, 포맷을 자동으로 처리하는 반면 비즈니스 로직은 급여계산 한다든지 하는 보이지 않는 어떤 처리를 하는 겁니다. 만약 EJB를 사용하기 위해 웹로직 서버를 이용한다고 하면 프로그램 개발자는 웹로직 서버의 컨테이너를 이용하여 작업을 하게 되는데 이는 트랜잭션의 지원, 보안, 동시 접근 처리 등 비즈니스 로직을 처리하는데 있어 필요한 모든 것을 제공 한다고 보면 됩니다.

참고
http://i-bada.blogspot.com/2014/09/enterprise-javabeanejb.html



********************************

빈(bean)

빈: 자바로 작성되어진 컴포넌트들로 JSP페이지에서 디자인부분과 로직부분을 분리시키고, 재사용성을 높여 효율성을 높여줌.

-규격
- 클래스는 패키지화 하여야 한다.
- 멤버변수는 프로퍼티(Property)라 칭한다.
- 클래스는 필요에 따라 직렬화가 가능하다.
- 프로퍼티의 접근자는 private이다.
- 프로퍼티마다 getter/setter 가 존재해야 하며, 그 이름은 각각 get/set으로 시작해야 한다.
- 위의 프로퍼티 getter/setter 메서드의 접근자는 public이어야 한다.
- 외부에서 프로퍼티에 접근은 메서드를 통해서 접근한다.
- 프로퍼티는 반드시 읽기/쓰기가 가능해야 하지만, 읽기 전용인 경우 getter만 정의할 수 있다.
- getter의 경우 파라미터가 존재하지 않아야 하고, setter의 경우 한 개 이상의 파라미터가 존재한다.
- 프로퍼티의 형이 boolean일 경우 get 메서드 대신 is메서드를 사용해도 된다.

참고




2017년 10월 21일 토요일

ajax 예제(cot에서 쓰인 부분 정리)

커뮤니티 페이지(Cot)에서 ajax를 쓴 부분을 정리


게시물 조회시 댓글을 ajax방식으로 호출 했다.
1
2
3
4
5
6
7
8
9
10
11
//게시물 조회시 댓글 호출    
function listReply() {
        $.ajax({
            type : "get",
            url : "${path}/freereply/list.do?bnum=${dto.bnum}",
            success : function(result) {
                // responseText가 result에 저장됨.
                $("#listReply").html(result);
            }
        });
    }
cs

type은 통신 타입이다. POST 또는 GET을 선택할 수 있다.
url은 요청할 url로 글번호(bnum)에 맞는 댓글들을 불러오는 컨트롤러로 연결된다.
success는 성공적으로 요청/응답이 되면 listReply 부분에 결과를 html형식으로 표시한다.
해당 jsp에서는 

<!-- 댓글 목록 위치 -->
<div id="listReply"></div>

으로 댓글 목록을 위치시켰다.



댓글 수정화면 댓글의 댓글 창또한 ajax를 이용해 새로고침 없이 창을 보이게 하였다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 댓글 수정화면 생성 
function showReplyModify(rnum) {
    $.ajax({
        type : "get",
        url : "${path}/freereply/detail/" + rnum,
        success : function(result) {
            $("#modifyReply").html(result);
            // 태그.css("속성", "값")
            $("#modifyReply").css("visibility""visible");
        }
    })
}
// 댓글의  코멘트 생성 
function showReplyComment(rnum) {
    $.ajax({
        type : "get",
        url : "${path}/freereply/commentwrite/" + rnum,
        success : function(result) {
            $("#ReplyComment").html(result);
            // 태그.css("속성", "값")
            $("#ReplyComment").css("visibility""visible");
        }
    })
}
cs
형태는 위와 비슷하다. 


로그인을 사이드 메뉴에서 구현하였다. 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function signin() {
            if($("#user_id").val()==""){
                alert("아이디를 입력해주세요.");
                $("#user_id").focus();
                }else if($("#password").val() ==""){
                    alert("비밀번호를 입력해주세요");
                    $("#password").focus();
                    
                    }else{
            $.ajax({
                url : './j_spring_security_check',
                data : $('form input').serialize(),
                type : 'POST',
                dataType : 'json',
               
            }).done(function(body) {
                var message = body.response.message;
                var error = body.response.error;
                if (error)
                    get_msg(message);
                if (error == false) {
                    var url = '${referer}';
                    if (url == '')
                        url = '<c:url value="/users/mypage" />';
                    location.href = url;
                }
            });
         }
        }
cs
앞의 if문은 아이디 비밀번호 체크이므로, ajax부터 본다면, 

data는 서버에 요청시 보낼 파라미터이다.
dataType은 응답 받을 데이터 타입을 선택한다.(XML, TEXT, HTML, JSON 등) 

아까랑 다르게 success가 아닌 done인데 같은의미인데 순서가 다른 것 같다.
검색해보니 success error 보다는 done fail 패턴이 동일한 요청에 대해 여러 성공 콜백을 호출할 때 함수 배열을 통해 더 깔끔?하게 처리해서 최근 done이 많이 쓰이는 것 같다...


beforesend에 대해서도 찾아볼 것 

2017년 10월 16일 월요일

TDD이란? / Junit 연습. 예제

먼저 테스트 주도 개발(TDD, Test Driven Development)란??

-설계 이후 코드 개발 및 테스트 케이스를 작성하는 기존의 개발 프로세스와 다르게 테스트 케이스를 작성한 후 실제 코드를 개발하여 리펙토링 하는 절차

[기존]


[TDD]

TDD장점은?

-작업과 동시에 테스트를 진행함으로써 실시간으로 오류를 파악할 수 있음
-짧은 개발주기를 통해 고객의 요구사항을 빠르게 수용하거나 피드백을 줄 수 있고, 현재 상황을 쉽게 파악할 수 있음
-자동화 도구를 이용해 TDD의 테스트 케이스를 단위테스트로 사용가능
[JUnit, cppUnit, NUnit 등]


단점은? 

-기존의 개발 프로세스에 테스트 케이스 설계까지 추가되므로 코드 생산 비용이 높아짐

>>하지만 객체지향적인 코딩 능력을 향상시킬 수 있다고 한다. 



////////////////////////////////////////////////////////////////

<Junit을 이용한 기본테스트>

간단한 계산기 자바 코드가 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.net.mypage;
public class Calculator {
    int add(int i, int j){
        return i+j;
    }
    
    int subtract(int i, int j){
        return i- j;
    }
    
    int multiply(int i, int j){
        return i*j;
        
    }
    
}
cs
이것을 테스트하려면 상단 메뉴의 New Java Class 부분의 JUnit Test case를 생성하면 된다. 


그 후 이렇게 코드 작성 후 Run As 부분의 JUnit test를 통해 테스트 가능하다 .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.net.mypage;
import static org.junit.Assert.*;
import org.junit.Test;
public class CalculatorTest {
    
    @Test
    public void add() {
        Calculator cal = new Calculator();
        int res = cal.add(24);
        //과거 였으면 sys.out으로 확인했겠지만 junit은 assert를 통해 (기대하는 값, 결과 값) 으로 확인할 수 있음 
        assertEquals(6, res);
        
    }
    
}
테스트 성공시 이런 화면이 보이고 실패시 failures 부분에 숫자가 올라간다.



<테스트 독립성>

Before와 after 어노테이션을 통해 test메소드 실행하기 전과 후 처리를 해줄 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.net.mypage;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class CalculatorTest {
    private Calculator cal;
    
    
    //before를 통해 test 메소드가 실행될때마다 setup이라는 메소드가 호출됨  cal 초기화 작업을 매번함 (선 처리 작업)
    @Before 
    public void setup(){
        cal = new Calculator();
        System.out.println("setup");
    }
    
    
    @Test
    public void add() {
        
        assertEquals(8, cal.add(17));
        System.out.println("add!");
    }
    
    @Test
    public void mul() {
        
        assertEquals(8, cal.multiply(18));
        System.out.println("multiply");
    }
    //after는 test메소드 실행 후 실행됨 (후처리 작업) >>before와 after를 통해 테스트 독립성 제공 
    @After
    public void after(){
        System.out.println("after");
    }
    
    
}
cs


콘솔창으로 보는 메소드 실행 순서

Test메소드 실행하기 전 Before가 선언된 setup메소드 실행 > test 실행 > after 실행
두번째 test 실행하기 전 다시 before 실행 > test 실행 > after 실행