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 이나 그 주변 값 또는 정수의 최대값, 최소값 등으로 테스트해보면 도움이 될 때가 많음. 

댓글 없음:

댓글 쓰기