2018년 3월 24일 토요일

modelandview란?

ModelAndView

org.springframework.web.servelt 패키지에 속해있는 클래스로 컨트롤러의 처리결과를 보여줄 뷰와 전달할 값을 저장할 용도로 쓰인다.
ModelAndView클래스를 보면 다음과 같이 구성되어 있다.
package org.springframework.web.servlet;

import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;

public class ModelAndView {
    private Object view;
    private ModelMap model;
    private HttpStatus status;
    private boolean cleared = false;

    public ModelAndView() {
    }

    public ModelAndView(String viewName) {
        this.view = viewName;
    }

    public ModelAndView(View view) {
        this.view = view;
    }

    public ModelAndView(String viewName, Map<String, ?> model) {
        this.view = viewName;
        if (model != null) {
            this.getModelMap().addAllAttributes(model);
        }

    }

    public ModelAndView(View view, Map<String, ?> model) {
        this.view = view;
        if (model != null) {
            this.getModelMap().addAllAttributes(model);
        }

    }

    public ModelAndView(String viewName, HttpStatus status) {
        this.view = viewName;
        this.status = status;
    }

    public ModelAndView(String viewName, Map<String, ?> model, HttpStatus status) {
        this.view = viewName;
        if (model != null) {
            this.getModelMap().addAllAttributes(model);
        }

        this.status = status;
    }

    public ModelAndView(String viewName, String modelName, Object modelObject) {
        this.view = viewName;
        this.addObject(modelName, modelObject);
    }

    public ModelAndView(View view, String modelName, Object modelObject) {
        this.view = view;
        this.addObject(modelName, modelObject);
    }

    public void setViewName(String viewName) {
        this.view = viewName;
    }

    public String getViewName() {
        return this.view instanceof String ? (String)this.view : null;
    }

    public void setView(View view) {
        this.view = view;
    }

    public View getView() {
        return this.view instanceof View ? (View)this.view : null;
    }

    public boolean hasView() {
        return this.view != null;
    }

    public boolean isReference() {
        return this.view instanceof String;
    }

    protected Map<String, Object> getModelInternal() {
        return this.model;
    }

    public ModelMap getModelMap() {
        if (this.model == null) {
            this.model = new ModelMap();
        }

        return this.model;
    }

    public Map<String, Object> getModel() {
        return this.getModelMap();
    }

    public void setStatus(HttpStatus status) {
        this.status = status;
    }

    public HttpStatus getStatus() {
        return this.status;
    }

    public ModelAndView addObject(String attributeName, Object attributeValue) {
        this.getModelMap().addAttribute(attributeName, attributeValue);
        return this;
    }

    public ModelAndView addObject(Object attributeValue) {
        this.getModelMap().addAttribute(attributeValue);
        return this;
    }

    public ModelAndView addAllObjects(Map<String, ?> modelMap) {
        this.getModelMap().addAllAttributes(modelMap);
        return this;
    }

    public void clear() {
        this.view = null;
        this.model = null;
        this.cleared = true;
    }

    public boolean isEmpty() {
        return this.view == null && CollectionUtils.isEmpty(this.model);
    }

    public boolean wasCleared() {
        return this.cleared && this.isEmpty();
    }

    public String toString() {
        StringBuilder sb = new StringBuilder("ModelAndView: ");
        if (this.isReference()) {
            sb.append("reference to view with name '").append(this.view).append("'");
        } else {
            sb.append("materialized View is [").append(this.view).append(']');
        }

        sb.append("; model is ").append(this.model);
        return sb.toString();
    }
}
다음과 같이 map에 데이터를 담거나 직접 값을 전달해 줄 수있다.
@RequestMapping(value="list")
  public ModelAndView list(@RequestParam(defaultValue="title") String searchOption,
    @RequestParam(defaultValue="") String keyword,
    @RequestParam(defaultValue="1") int curPage) throws Exception{

  //전달할 정보 가져오기
  int count = adminService.countboard(searchOption, keyword);
  BoardPage boardPage = new BoardPage(count, curPage);
  int start = boardPage.getPageBegin();
  int end = boardPage.getPageEnd();
  List<WebBoard> list = adminService.Viewlist(start, end, searchOption, keyword);

  //전달할 정보 map에 담기
  Map<String, Object> map = new HashMap<String, Object>();
  map.put("list", list);
  map.put("searchOption", searchOption);
  map.put("keyword", keyword);
  map.put("boardPage", boardPage);


  ModelAndView mav = new ModelAndView();

  //ModelAndView 객체에 전달할 정보(map)과 뷰 설정하기
  mav.addObject("map", map);
  //map에 넣지않고 직접 전달해도 된다.
  mav.addObject("count",count);
  mav.setViewName("/admin/adminmode");

  return mav;
  }
ModelAndView 외에도 다양하게 컨트롤러의 리턴타입을 정할 수 있음.
@ReqeustMapping("/list/")
  public String list(Model model){

    int count = adminService.countboard();

    model.addAttribute("count", count);

    return "/admin/adminmode"
  }

2018년 3월 4일 일요일

restcontroller

REST는 'Representational State Transfer' 의 약어로 하나의 URI는 하나의 고유한 Resource를 대표하도록
설계된다는 개념이다.
이 말은 다른 말로 'URI와 HTTP메소드를 이용해 객체화된 서비스에 접근한다고 말하는 것'이 라고 말할 수도 있는데
이 편이 더 쉽게 이해할 수도 있다.

REST API는 외부에서 특정 URI를 통해서 사용자가 원하는 정보를 제공하는 방식이다.
최근에 Open API에서 많이 사용되면서 REST 방식을 제공되는 외부 연결 URI를 REST API라고 하고,
REST 방식의 서비스 제공이 가능한 것을 'Restful' 하다고 표현한다.






예제( 다른 방법도 있는것같음 ) 
http://doublesprogramming.tistory.com/105

+++++

2018년 2월 8일 목요일

git branch 관련

브랜치란?
독립적인 여러 작업을 진행하기 위한 개념

여러 명이서 동시에 작업을 할 때에 다른 사람의 작업에 영향을 주거나 받지 않도록, 먼저 메인 브랜치에서 자신의 작업 전용 브랜치를 만듭니다. 그리고 각자 작업을 진행한 후, 작업이 끝난 사람은 메인 브랜치에 자신의 브랜치의 변경 사항을 적용합니다. 이렇게 함으로써 다른 사람의 작업에 영향을 받지 않고 독립적으로 특정 작업을 수행하고 그 결과를 하나로 모아 나가게 됩니다. 이러한 방식으로 작업할 경우 '작업 단위', 즉 브랜치로 그 작업의 기록을 중간 중간에 남기게 되므로 문제가 발생했을 경우 원인이 되는 작업을 찾아내거나 그에 따른 대책을 세우기 쉬워집니다.


>>결국 개발자들이 서로에 작업에 영향을 주지 않으면 독립된 공간에서 다양한 작업을 진행할 수 있게 도와주는 것 같음


master - 최종 배포용
develop - 개발용
feature - develop에서 새로운 기능을 만들때 쓰는 브랜치?

*************************************
출처
https://backlog.com/git-tutorial/kr/stepup/stepup1_1.html


브랜치 설명
https://mylko72.gitbooks.io/git/content/branch/branch_type.html




**********************************************
쓰는 흐름은
develop에서  feature를 따서 작은 기능을 개발 -> 작은 기능이 개발완료되면 develop으로 merge -> 반복 -> 모든 기능들이 완료되어 develop으로 합쳐지고, 정상적으로 동작하면 master에 올려서 최종배포

인듯 하다.

2018년 1월 21일 일요일

git에서 공유받은 maven dependencies / missing artifact 문제

http://parkpurong.tistory.com/133

깃으로 받은 프로젝트의 maven dependencies가 제대로 안받아지는것같다 ㅠ
위 블로그 방법으로해서 Missing artifact  는 없앴는데 계속안되서 그냥 내 로컬프로젝트 중 하나 pom.xml에서 버전 바꿔서 새버전 다시 받고 했음...

2017년 11월 29일 수요일

토비의 스프링 공부/정리 [3]

회사에서 토비의 스프링 스터디를 시작하였다.
새로운 기분으로 정독하고 있으며, 정리한 내용을 학습목적으로 git에 올리고 있다.
이해가 가지 않는 내용도 있지만, 일단 1회독을 마치는 것을 목표로 진행하자!









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


3. 템플릿


템플릿이란 바뀌는 성질이 다른 코드 중에서 변경이 거의 일어나지 않으며 일정한 패턴으로 유지되는 특성을 가진 부분을 자유롭게 변경되는 성질을 가진 부분으로 독립시켜서 효과적으로 활용할 수 있도록하는 방법. (??)
3장에선 스프링에 적용된 템플릿 기법을 살펴보고, 이를 적용해 완성된 DAO코드를 만드는 방법을 소개한다.


3.1 다시 보는 초난감 DAO

책에서 소개한 UserDao 코드에는 예외상황에 대한 처리 부분에 문제점이 있다고 한다.
preparedstatement를 처리하는 중 예외가 발생하면 close를 실행못하고 마치게된다. 이것이 계속쌓이면 리소스가 부족하다는 오류가 발생할 수 있다. 그래서 try/catch 구문으로 예외처리를 하도록 권장한다.
글 조회부분 또한 ResultSet도 반환해야하는 리소스이기 때문에 예외상황에서도 ResultSet의 close()메소드가 반드시 호출되도록 만들어줘야 한다.

리소스 반환과 close()

Connection이나 PreStatement에는 close()메소드가 있다. 종료라고 볼 수도 있지만 보통 리소스를 반환한다는 의미로 이해하는 것이 좋다. Connection과 PreparedStatement는 보통 풀(pool) 방식으로 운영된다. 미리 정해진 풀 안에 제한된 수의 리소스(Connection, Statement)를 만들어 두고 필요할 때 이를 할당하고, 반환하면 다시 풀에 넣는 방식으로 운영된다. 요청이 매우 많은 서버 환경에서는 매번 새로운 리소스를 생성하는 대신 풀에 미리 만들어둔 리소스를 돌려가며 사용하는 편이 훨씬 유리하다. 대신. 사용한 리소스는 빠르게반환해야 한다. 그렇지 안흥면 풀에 있는 리소스가 고갈되고 결국 문제가 발생한다. close()메소드는 사용한 리소스를 풀로 다시 돌려주는 역할을 한다.

3.2 변하는 것과 변하지 않는 것

finally 블록의 c.close() 라인 하나 빼먹은 것과 같은 실수를 했어도 테스트를 돌려보면 별 문제가 없어 보인다. 하지만 해당 메소드가 호출되고 나면 커넥션이 하나씩 반환되지 않고 쌓여가게 된다. 이를 그대로 사용하면 최대 DB커넥션 개수를 넘어설 것이고, 서버에서 리소스가 꽉 찼다는 에러가 나면서 서비스가 중단되는 상황이 발생한다.
>>이런 예외상황을 처리하는 코드는 테스트하기 매우 어렵고 번거롭다.
>> 효과적으로 다루기위해선..??

분리와 재사용을 위한 디자인 패턴 적용

책에서는 UserDao의 메소드를 개선하고 있다.
*****어려움 ㅠㅠ

3.3 JDBC 전략 패턴의 최적화


3.4 컨텍스트와 DI


3.5 템플릿과 콜백


3.6 스프링의 JdbcTemplate

2017년 11월 6일 월요일

토비의 스프링 공부/정리 2장

회사에서 토비의 스프링 스터디를 시작하였다.
새로운 기분으로 정독하고 있으며, 정리한 내용을 학습목적으로 git에 올리고 있다.
이해가 가지 않는 내용도 있지만, 일단 1회독을 마치는 것을 목표로 진행하자!



2. 테스트

저자는 스프링이 개발자에게 제공하는 것들 중 객체지향과 테스트가 가장 중요한 가치라고 하며 2장을 시작한다.
스프링으로 개발을 하면서 테스트를 만들지 않는다면 이는 스프링이 지닌 가치의 절반을 포기하는 셈이다.

테스트란? 
- 코드의 결함 제거(디버깅) --> 의도한대로 나올 수 있도록 수정해 나가는 작업 
- 내가 예상하고 의도했던 대로 코드가 정확히 동작하는지를 확인해서 만든 코드를 확신할 수 있게 해주는 작업 

책에서는 웹을 통한 DAO테스트 방법의 2가지 문제점에 대해 말하고 있다. 
1. 수동 확인 작업의 번거로움: 테스트 결과를 확인하는 작업을 사람의 눈으로 해야함. 
2. 실행 작업의 번거로움: 전체 기능을 테스트해보기 위해 main 메소드를 수백 번 실행하는 수고가 필요함.
  • ++DAO뿐만 아니라 서비스 클래스, 컨트롤러, 뷰 등 모든 레이어의 기능을 다 만들고 나서야 테스트가 가능 (이 경우 오류가 발생했을 때 어느부분에서 오류가 발생하였는지 파악이 어렵고, 빠르고 정확히 대응하기 어려움)
단위테스트란?(Unit Test)
- 작은 단위의 코드에 대해 테스트를 수행한 것
- 테스트의 관심이 다르다면 테스트할 대상을 분리하고 집중해서 접근해야한다.
- 단위 테스트를 하는 이유는 개발자가 설계하고 만든 코드가 원래 의도한 대로 동작하는지를 
개발자 스스로 빨리 확인 받기 위해서이다.
이 후 이 2가지 문제점에 대해 개선하는 작업을 보여주고 있다.
  1. 테스트 검증의 자동화
    • 테스트의 결과 값들을 사람의 눈으로 직접 확인하는 것이 아닌 테스트 수행과 기대하는 결과에 대한 확인까지 해주는 코드로 된 자동화된 테스트를 해야한다고 하고있다.
  2. 테스트의 효율적인 수행과 결과 관리
  • main() 메소드를 이용한 테스트 작성 방법만으로는 애플리케이션 규모가 커지고 테스트 개수가 많이지면 테스트를 수행하는 일이 점점 부담이 된다며, JUnit 을 소개하고있다.
JUnit 프레임워크
자바 테스팅 프레임워크로 JUnit을 통해 단위테스트가 가능하다.
책에서는 스프링을 학습하고 제대로 활용하려면 최소한의 JUnit 테스트 작성 방법과 실행방법은 알고있어야한다고 하고있다.
스프링의 핵심 기능 중 하나인 스프링 테스트 모듈도 JUnit을 이용하고 있다고 한다.
JUnit의 간단한 사용법과 테스트 방법을 설명한 후 테스트 결과의 일관성을 설명하고 있다. 
(책에서는 사용자를 추가하는 테스트를 수행하고있는데, 한번 수행 후 또 다시 테스트를 실행시키면 사용자가 중복되기 때문에 문제가 발생하기 때문에 테스트 전에 등록된 사용자 정보를 초기화 시켜주는 작업을 하여 동일한 테스트 결과를 나타날 수 있게 하는 과정을 설명하고있다.)
  - 반복적으로 테스트를 수행하였을 때, 항상 동일한 결과가 나와야한다.
  - 단위테스트는 코드가 바뀌지 않는다면 매번 실행할 때마다 동일한 테스트 결과를 얻을 수 있어야 한다.
"항상 네거티브 테스트를 먼저 만들라" 
부정적인 케이스를 먼저 만드는 습관을 들이는게 좋다.
테스트 주도 개발(Test Driven Development-TDD)이란?
만들고자 하는 기능의 내용을 담고 있으면서 만들어진 코드를 검증도 해줄 수 있도록
테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발 방법
("실패한 테스트를 성공시키기 위한 목적이 아닌 코드는 만들지 않는다")
TDD의 장점
 코드를 만들어 테스트를 실행하는 그 사이의 간격이 매우 짧다.
(오류를 빨리 발견할 수 있다.)

스프링은 JUnit을 이용하는 테스트 컨텍스트 프레임워크를 제공한다. 라고하며, 의존성 주입을 이용한 테스트를 소개하고 있다. (이 부분은 직접 실습을 해보면서 하는 게 좋을 듯 하다.)
@Autowired가 잠깐 나오는데, 2권에서 자세하게 설명한다고 되어 있다.
- Autowired 가 붙은 인스턴스 변수가 있으면, 테스트 컨텍스트 프레임워크는 변수 타입과 일치하는 컨텍스트 내의 빈을 찾는다. 
타입이 일치하는 빈이 있으면 인스턴스 변수에 주입해준다.

학습테스트(learning test)란?
자신이 만들지 않은 프레임워크나 다른 개발팀에서 만들어서 제공한 라이브러리 등에 대해서는 테스트를 작성해야한다.

-목적: 자신이 사용할 API나 프레임워크의 기능을 테스트로 보면서 사용 방법을 익히려는 것
-장점
1. 다양한 조건에 따른 기능을 손십게 확인 가능
2. 학습 테스트 코드를 개발 중에 참고할 수 있음.
3. 프레임워크나 제품을 업그레이드할 때 호환성 검증을 도와줌.
4. 테스트 작성에 대한 좋은 훈련이 됨.
5. 새로운 기술을 공부하는 과정이 즐거워짐.

버그테스트(bug test)란?
코드에 오류가 있을 때 그 오류를 가장 잘 드러내줄 수 있는 테스트
(일단 실패하도록 만들어야함. 그 후 성공할 수 있도록 애플리케이션 코드를 수정함.)
필요성과 장점
1. 테스트의 완성도를 높여줌
2. 버그의 내용을 명확하게 분석하게 해줌
3. 기술적인 문제를 해결하는 데 도움이 됨


동등분할: 같은 결과를 내는 값의 범위를 구분해서 각 대표값으로 테스트 하는 방법

경계값 분석: 에러는 동등분할 범위의 경계에서 주로 많이 발생한다는 특징을 이용해서 경계의 근처에 있는 값을 이용해 테스트하는 방법.







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


2. 테스트

스프링이 개발자에게 제공하는 가장 중요한 가치는? >> 객체지향과 테스트
스프링은 IoC/Di를 이용해 객체지향 프로그래밍 언어의 근본과 가치를 개발자가 손쉽게 적용하고 사용할 수 있게 도와주는 기술, 동시에 복잡한 엔터프라이즈 애플리케이션을 효과적으로 개발하기 위한 기술. 
테스트는 스프링이 강조하고 가치를 두고 있다. 테스트를 통해 만들어진 코드를 확신할 수 있게 해주고, 변화에 유연하게 대처할 수 있는 자신감을 준다. 
2장에서는 테스트란 무엇이며, 그 가치와 장점, 활용 전략, 스프링과의 관계를 살펴본다.

2.1 UserDaoTest 다시보기

테스트란 내가 예상하고 의도했던 대로 코드가 정확히 동작하는지를 확인해서, 만든 코드를 확신할 수 있게 해주는 작업. 테스트의 결과가 원하는대로 나오지 않을 경우 코드나 설계에 결함이 있음을 알 수 있음. 이를 통해 코드의 결함을 제거해가는 작업, 일명 디버깅을 거치게 되고, 결국 최종적으로 테스트가 성공하면 모든 결함이 제거됐다는 확신을 얻을 수 있음.

웹을 통한 DAO테스트 방법의 문제점

DAO뿐만 아니라 서비스 클래스, 컨트롤러, JSP 뷰 등 모든 레이어의 기능을 다 만들고나서 테스트가 가능하다. 이 때문에 테스트도중 에러가 발생하면 에러를 간단히 찾을 수 없게 된다. >> 다른 계층의 코드와 컴포넌트, 심지어 서버의 설정 상태까지 모두 테스트에 영향을 줄 수 있기 때문에 이런 방식으로 테스트하는 것은 번거롭고, 오류가 있을 때 빠르게 대응이 어렵다.

작은 단위의 테스트

테스트는 가능하면 작은 단위로 쪼개어 집중해서 할 수 있어야 한다. 관심사의 분리라는 원리는 여기에도 적용됨. 
작은 단위의 코드에 대해 테스트를 수행한 것을 단위 테스트라 한다. 
>> 단위 테스트 없이 긴 테스트를 수행하는 경우, 수많은 에러가 발생하거나 에러가 안나지만 기능이 제대로 동작하지 않을 수 있음. 이때 문제의 원인을 찾기 힘들다.  하지만 단위 별로 테스트를 진행한 후 긴 테스트를 한다면, 에러나 실패가 발생할 수 도 있겠지만, 이미 각 단위별로 검증을 마친 상태이므로 훨씬 더 나을 것임이다.

자동수행 테스트 코드

테스트는 자동으로 수행되도록 코드로 만들어지는 것이 중요함.
번거로운 작업 없이 테스트를 빠르게 실행 할 수 있기 때문에 언제든 코드를 수정하고나서 테스트를 해볼 수 있음. 

지속적인 개선과 점직적인 개발을 위한 테스트

테스트를 통해 기능을 추가해가면서 점직적인 개발이 가능하고 기존에 만들었던 기능에 영향을 주지 않고 확인할 수 있음.


책에서 소개한 UserDaoTest의 문제점을 서술하고 있다.

수동확인 작업의 번거로움: 테스트의 수행은 자동으로 진행되지만 결과확인은 사람의 책임이므로 완전히 자동으로 테스트되는 방법이라고 할 수 없음.

실행 작업의 번거로움: 매번 main() 메소드를 실행하는 것은 분거로움으로 좀 더 편리하고 체계적으로 테스트를 실행하고 그 결과를 확인하는 방법이 필요.

2.2 UserDaoTest 개선

테스트 검증의 자동화

책에선 가져오는 오브젝트의 값을 비교해서 확인하는 것을 추가하여 첫번째 문제점인 결과확인 작업까지 테스트 코드에 추가하였다. 

테스트의 효율적인 수행과 결과 관리

좀 더 편리하게 테스트를 수행하고 편리하게 결과를 확인하려면 단순한 main 메소드로는 한계가 있음. 일정한 패턴을 가진 테스트를 만들 수 있고, 많은 테스트를 간단히 실행시킬 수 있으며, 테스트 결과를 종합해서 볼 수 있고, 테스트가 실패한 곳에서 빠르게 찾을 수 있는 기능을 갖춘 테스트 지원 도구와 그에 맞는 테스트 작성 방법이 필요.
자바에서는 실용적인 테스트를 위한 도구가 여러가지 존재함. >> JUnit를 통해 자바로 단위 테스트를 만들 때 유용하게 쓸 수 있다.

JUnit 테스트로 전환

JUnit은 프레임워크이다. 1챕터에서 프레임워크의 기본 동작원리가 바로 제어의 역전(IoC)라고 했다. 프레임워크는 개발자가 만든 클래스에 대한 제어 권환을 넘겨받아서 주도적으로 애플리케이션의 흐름을 제어한다. 개발자가 만든 클래스의 오브젝트를 생성하고 실해아는 일은 프레임워크에 의해 진행된다. 따라서 프레임워크에서 동작하는 코드는 main()메소드가 필요 없고 오브젝트를 만들어서 실행시키는 코드를 만들 필요도 없다.


테스트 메소드 전환

기존의 책에서 소개한 main()메소드 테스트는 이런 면에서 프레임워크에 적용하기에 적합하지 않다. >> 테스트가 main()메소드로 만들어졌다는 것은 제어권을 직접 갖는다는 의미이기 때문
책에서 새로 만들 테스트 메소드는 JUnit 프레임워크가 요구하는 조건 두 가지를 따라야한다고 한다. 1. 메소드가 public으로 선언 2. 메소드에 @Test라는 어노테이션 붙이기


검증 코드 전환

책에서 앞서 소개한 결과를 확인할 때 사용한 if/else문을 asserThat이라는 스태틱 메소드를 이용해 변경하고 있다. 

2.3 개발자를 위한 테스팅 프레임워크 JUnit

스프링을 학습하고 제대로 활용하려면 최소한의 JUnit 테스트 작성 방법과 실행 방법은 알고 있어야 한다.
JUnitCore(JUnit API 인듯?)를 이용해 테스트를 실행하고 콘솔에 출력된 메시지를 보고 결과를 확인하는 ㅂ아법은 가장 간단하긴 하짐나 테스트의 수가 많아지면 관리하기 힘들어지므로 자바 IDE에 내장된 JUnit 테스트 지원도구를 사용하는 것이 좋다.

IDE
이클립스에서 @Test가 들어있는 테스트클래스를 선택한 뒤 run as 항목 중 junit test를 선택하면 테스트를 실행시킬 수 있다. >> 테스트의 총 수행시간, 실행한 테스트의 수, 테스트 에러의 수, 테스트 실패의 수를 확인할 수 있음.
빌드 툴
프로젝트의 빌드를 위해 ANT나 메이븐 같은 빌드 툴과 스크립트를 사용하고 있다면, 빌드 툴에서 제공하는 JUnit 플러그인이나 태스크를 이용해 JUnit테스트를 실행할 수 있다.
>>여러 개발자가 만든 코드를 통합해서 테스트를 수행해야할 때는 서버에서 모든 코드를 가져와 통합하고 빌드한 뒤에 테스트를 수행하는 것이 좋다고 함...


테스트 결과의 일관성

데이터베이스를 사용하는 테스트 후 데이터가 남아있다면 다음 테스트 때 오류가 발생할 수 도 있기때문에 테스트 후 이전상태의 데이터로 만들어줘야 한다. 
책에선 deleteAll()라는 메소드를 추가하여 데이터를 지우고 테스트를 시작한다.


>>개발자는 빨리 테스트를 만들어 성공하는 것을 보고 다음 기능으로 나아가고 싶어하기 때문에, 긍정적인 경우를 골라서 성공할만한 테스트를 먼저 작성하게 되기 쉽다. 그래서 테스트를 작성할 때 부정적인 케이스를 먼저 만드는 습관을 들이는 것이 좋다고 함. (ex id를 정확하게 가져오는 것도 중요하지만, 존재하지 않는 id가 주어졌을때 어떻게 반응할지를 먼저 결정하고 이를 확인할 수 있는 테스트를 만들려고 한다면 예외적인 상황을 빠뜨리지 않는 꼼꼼한 개발이 가능하다고 한다.


테스트 주도 개발(Test Driven Development, TDD)

만들고자 하는 긴으의 내용을 담고 있으면서 만ㄷ느렁진 코드를 검증도 해줄 수 있도록 테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발 방법.
>>아예 테스트를 먼저 만들고 그 테스트가 성공하도록 하는 코드만 만드는 식으로 진행

JUnit이 하나의 테스트 클래스를 가져와 테스트를 수행하는 방식

1. 테스트 클래스에서 @Test가 붙은 public이고 void형이며 파라미터가 없는 테스트 메소드를 모두 찾는다.
2. 테스트 클래스의 오브젝트를 하나 만든다.
3. @before가 붙은 메소드가 있으면 실행한다.
4. @Test가 붙은 메소드를 하나 호출하고 테스트 결과를 저장해둔다.
5. @After가 붙은 메소드가 있으면 실행한다.
6. 나머지 테스트 메소드에 대해 2~5번을 반복
7. 모든 테스트의 결과를 종합해서 돌려준다. 

픽스처

테스트를 수행하는데 필요한 정보나 오브젝트
>>책에선 테스트를 하기위한 유저정보(픽스처인듯?)를 @Before 를 통해 선언

2.4 스프링 테스트 적용

테스트를 위한 애플리케이샨 컨텍스트 관리

책에서 DI를 통해 오브젝트를 주입받아 테스트를 하는 방법을 소개하고 있다.
(생략 or 더 추가??)

@Autowired

스프링의 DI에 사용되는 특별한 어노테이션, @Autowired가 붙은 인스턴스 변수가 있으면, 테스트 컨텍스트 프레임워크는 변수 타입과 일치하는 컨텍스트 내의 빈을 찾는다. 타입이 일치하는 빈이 있으면 인스턴스 변수에 주입해준다.  


침투적 기술과 비침투적 기술

침투적(invasive) 기술은 기술을 적용했을 때 애플리케이션 코드에 기술 관련 API가 등장하거나, 특정 인터페이스나 크랠스를 사용하도록 강제하는 기술, 침투적 기술을 사용하면 애플리케이션 코드가 해당 기술에 종속되는 결과를 가져옴
비침투적(noninvasive) 기술은 애플레키에션 로직을 담은 코드에 아무런 영향을 주지 않고 적용가능. 따라서 기술에 종속적이지 않은 순수한 코드를 유지 
스프링은 비침투적 기술의 대표적 예
>>책에서 @autowird를 이용하지 않고 직접 오브젝트를 생성하여 테스트하는 방법을 소개하고 있다. 

(책에선 DI를 테스트에 이용하는 세가지 방법을 소개한 후 장점들을 소개하였음.)


2.5 학습 테스트로 배우는 스프링

학습테스트: 자신이 만들지 않은 프레임워크나 다른 개발팀에서 만들어서 제공한 라이브러리 등에 대해서도 테스트를 작성하는 것
>> 이를 통해 자신이 사용할 API나 프레임워크의 기능을 테스트로 보면서 사용방법을 익히려는 것


학습테스트의 장점

1. 다양한 조건에 따른 기능을 손쉽게 확인해 볼 수 있음.
2. 학습 테스트 코드를 개발 중에 참고할 수 있음.
3. 프레임워크나 제품을 업그레이드할 때 호환성 검증을 도와줌.
4. 테스트 작성에 대한 좋은 훈련이 됨.
5. 새로운 기술을 공부하는 과정이 즐거워짐. 


버그테스트

코드에 오류가 있을 때 그 오류를 가장 잘 드러내줄 수 있는 테스트.
버그테스트는 버그가 원인 되서 테스트가 실패하는 코드를 만들도록 해야함. 이 후 버그 테스트가 성공할 수 있도록 애플리케이션의 코드를 수정한다. 

버그테스트의 장점
1. 테스트의 완성도를 높여줌.
2. 버그의 내용을 명확하게 분석하게 해줌.(버그로 인해 발생할 수 있는 다른 오류들을 발견할 수 있고 이를 테스트의 중요한 기법 중의 하나인 동등분할이나 경계값 분석을 적용해 볼 수 있음)
3. 기술적인 문제를 해결하는데 도움.

동등분할(equivalence partitioning)
같은 결과를 내는 값의 범위를 구분해서 각 대표 값으로 테스트하는 방법. 어떤 작업의 결과의 종류가 true, false 또는 예외발생 세가지라면 각 결과를 내는 입력 값이나 상황의 조합을 만들어 모든 경우에 대한 테스트를 해보는 것이 좋다.
경계값 분석(boundary value analysis) 
에러는 동등 분할 범위의 경게에서 주로 많이 발생한다는 특징을 이용해서 경계의 근처에 있는 값을 이용해 테스트하는 방법. 보통 숫자의 입력 값인 경우 0 이나 그 주변 값 또는 정수의 최대값, 최소값 등으로 테스트해보면 도움이 될 때가 많음.