SlideShare a Scribd company logo
1 of 58
Download to read offline
단위테스트
최용은
시작하자!
SpringCamp 2014
단위 테스트란?
사전적 의미
1) 제품의 성능이나 상태 따위를 일정한 기준에 따라 검사함
2) 일정한 기준에 따라 검사하다.
1) 사물의 길이, 넓이, 무게 등을 수치로 나타낼 때, 기본이 되는 기준
2) 하나의 집단 조직 등을 구성하는 기본적인 한덩어리.
단위
테스트
출처 : Daum 사전
위키백과
유닛 테스트(unit test)
컴퓨터 프로그래밍에서 소스코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검
증하는 절차다.
즉, 모든 함수와 메소드에 대한 테스트 케이스를 작성하는 절차를 말한다.
…..
그림으로 보면..
출처 : http://martinfowler.com/bliki/UnitTest.html
목적?
출처 : wikitree.co.kr/main/news_view.php?id=70077
목 적!
신 뢰
단위테스트를 작성하지 않은 이유 ?
● 단위테스트가 무엇인지 모른다.
● 들어봤지만, 주변에 작성하는 사람이 없다.
● 작성하고자 하지만, 너무 어렵다.
○ 어디서 어떻게 시작해야할지 모르겠다.
● 작성할 줄 알지만,
○ 귀찮다. -> 습관을 들여야한다...
○ 필요 없다. -> 천재...
오 해 기능 추가 시간이 너~ 무 오래 걸린다.
오 해 기능 추가 시간이 너~ 무 오래 걸린다.
테스트 코드량이 많아져서, 별로...
오 해 기능 추가 시간이 너~ 무 오래 걸린다.
테스트 코드량이 많아져서, 별로...
단위 테스트만 작성하면 버그 따윈 없어!
단위 테스트를 작성해 볼까요?
단위 테스트를 도와 주는 도구 for JAVA
● JUnit
○ (자바) 단위 테스트 프레임워크의 표준
○ http://junit.org/
● Mocking Framework
○ Mockito
○ easyMock
○ JMock
○ ...
단순하게 생각하자.
예상하고,
단순하게 생각하자.
예상하고,
실행하고,
단순하게 생각하자.
예상하고,
실행하고,
검증하라!
예 : 상품 판매 금액/수량 계산하기
class SaleResult
private final long productId;
private long totalSalePrice;
private long totalSaleCount;
public SaleResult(long productId) {
this.productId = productId;
}
public void calculate(List<Sale> sales) {
for( Sale sale : sales ) {
totalSalePrice += sale.getSalePrice();
totalSaleCount += sale.getSaleCount();
}
}
// getter/setter 생략
class Sale
private long id;
private long productId;
private long salePrice;
private long saleCount;
public Sale(long id, long productId, long salePrice,
long saleCount) {
this.id = id;
this.productId = productId;
this.salePrice = salePrice;
this.saleCount = saleCount;
}
// getter/setter 생략
SaleResult 테스트
class SaleResult
private final long productId;
private long totalSalePrice;
private long totalSaleCount;
public SaleResult(long productId) {
this.productId = productId;
}
public void calculate(List<Sale> sales) {
for( Sale sale : sales ) {
totalSalePrice += sale.getSalePrice();
totalSaleCount += sale.getSaleCount();
}
}
// getter/setter 생략
class SaleResultTest
@Test public void calculate() throws Exception {
//given
long productId = 1l;
List<Sale> sales = new ArrayList<>();
sales.add(new Sale(1l, 1l, 10000l, 1l));
sales.add(new Sale(2l, 1l, 10000l, 1l));
SaleResult saleResult = new SaleResult(productId);
//when
saleResult.calculate(sales);
//then
assertThat(saleResult.getTotalSalePrice(), is(20000l));
assertThat(saleResult.getTotalSaleCount(), is (2l));
}
given / when / then
long productId = 1l;
List<Sale> sales = new ArrayList<>();
sales.add(new Sale(1l, 1l, 10000l, 1l));
sales.add(new Sale(2l, 1l, 10000l, 1l));
SaleResult saleResult = new SaleResult(productId);
saleResult.calculate(sales);
assertThat(saleResult.getTotalSalePrice(), is(20000l));
assertThat(saleResult.getTotalSaleCount(), is (2l));
given
when
then
long productId = 1l;
List<Sale> sales = new ArrayList<>();
sales.add(new Sale(1l, 1l, 10000l, 1l));
sales.add(new Sale(2l, 1l, 10000l, 1l));
SaleResult saleResult = new SaleResult(productId);
예상하기 (준비하기)
g
i
v
e
n
productId 1
totalSalePrice 0
totalSaleCount 0
SaleResult
실행하기
saleResult.calculate(sales);
w
h
e
n
public void calculate(List<Sale> sales) {
for( Sale sale : sales ) {
totalSalePrice += sale.getSalePrice();
totalSaleCount += sale.getSaleCount();
}
}
productId 1
totalSalePrice 20000
totalSaleCount 2
SaleResult
검증하기
assertThat(saleResult.getTotalSalePrice(), is(20000l));
assertThat(saleResult.getTotalSaleCount(), is (2l));
t
h
e
n
productId 1
totalSalePrice 20000
totalSaleCount 2
SaleResult
예제의 느낌
하지만 현실은
단위테스트가 어려운 이유들..
● 소프트웨어는 객체들이 얽히고, 설켜서, 복잡하다.
● 제어하기 힘든 것들
○ 영속성(Persistency)
○ 시간(Time)
○ 임의성(Randomness)
○ 네트워크(Network)
○ 인프라(Infra)
○ ...
테스트 더블
진짜 협
력 객체
테스트
더블
테스트
더블
테스트
더블
출처 : Effective Unit Testing
테스트 대상 코드와 협력 객체를 분리
● 테스트 작성 시 테스트 대상 코드와 상호작용하는 객체
테스트
대상 코드
테스트 더블 종류
스파이 객체스텁 객체 페이크 객체 목 객체
테스트 더블
출처 : Effective Unit Testing
테스트 더블 사용하기
● 테스트 대상 코드에서 어떻게 테스트 더블을 사용하
지?
테스트 더블 사용하기
● 테스트 대상 코드에서 어떻게 테스트 더블을 사용하
지?
○ 의존성 주입 (Dependency Injection, DI)
■ 객체간 종속성을 소스코드에서 설정하지 않고,
외부에서 주입하도록 하는 디자인 패턴 중 하나
테스트 더블 사용하기
● 의존성 주입 (Dependency Injection, DI)
○ 적용 유형
■ 생성자 주입
■ 세터(Setter)를 통한 주입
■ 인터페이스(Interface)를 통한 주입
테스트 더블 사용하기
● 의존성 주입 (Dependency Injection, DI)
○ 인터페이스를 통한 주입
<<interface>>
Ram
SamsungRam HynixRam
MotherBoard
1
4
테스트 더블 사용하기
● 의존성 주입 (Dependency Injection, DI)
class MotherBoard
private Ram ram;
public MotherBoard(Ram ram) {
this.ram = ram;
}
// 생성자 주입
class MotherBoard
private Ram ram;
public void setRam(Ram ram) {
this.ram = ram;
}
// 세터(setter) 주입
class MotherBoard
Ram ram = new HynixRam();
// 안티 패턴
MotherBoard b = new MotherBoard
(new SamsungRam());
MotherBoard b= new MotherBoard();
b.setRam(new HynixRam());
MotherBoard b= new MotherBoard();
테스트 더블을 이용해서 영속성 단위 테스트 해보자!
영속성에 대한 대처
SaleService
SaleResult
<<interface>>
SaleRepository
<<interface>>
SaleResultRepository
<<create>>
1
1
1
1
● 상품의 판매 금액/수량을 계산 하여, DB에 저장하기
영속성에 대한 대처
SaleService
SaleResult
<<interface>>
SaleRepository
<<interface>>
SaleResultRepository
<<create>>
1
1
1
1
● 상품의 판매 금액/수량을 계산 하여, DB에 저장하기
테스트 더블
진짜 협력객체
테스트 대상코드
SaleResult 저장하기
class SaleService
private final SaleRespository saleRespository;
private final SaleResultRepository saleResultRepository;
public SaleService(saleRespository,
saleResultRepository) {
this.saleRespository = saleRespository;
this.saleResultRepository = saleResultRepository;
}
public void generateSaleResult(long productId) {
List<Sale> sales = saleRespository.findAllByProductId
(productId);
if(sales.isEmpty()) {
throw new RuntimeException("sales is empty");
}
SaleResult saleResult = new SaleResult(productId);
saleResult.calculate(sales);
saleResultRepository.save(saleResult);
}
class SaleServiceTest
@Before public void setUp() throws Exception {
saleRespositoryMock = mock(SaleRespository.class);
saleResultRepositoryMock = mock(SaleResultRepository.class);
saleService = new SaleService(saleRespositoryMock,
saleResultRepositoryMock);
}
@Test public void generateSaleResult() throws Exception {
//given
List<Sale> sales = new ArrayList<>();
sales.add(new Sale(1l, 1l, 10000l, 1l));
given(saleRespositoryMock.findAllByProductId(productId)).willReturn(sales);
//when
saleService.generateSaleResult(productId);
//then
verify(saleRespositoryMock, times(1)).findAllByProductId(productId);
verify(saleResultRepositoryMock,times(1)).save(any(SaleResult.class));
}
SaleResult 저장하기
class SaleService
private final SaleRespository saleRespository;
private final SaleResultRepository saleResultRepository;
public SaleService(saleRespository,
saleResultRepository) {
this.saleRespository = saleRespository;
this.saleResultRepository = saleResultRepository;
}
public void generateSaleResult(long productId) {
List<Sale> sales = saleRespository.findAllByProductId
(productId);
if(sales.isEmpty()) {
throw new RuntimeException("sales is empty");
}
SaleResult saleResult = new SaleResult(productId);
saleResult.calculate(sales);
saleResultRepository.save(saleResult);
}
class SaleServiceTest
@Before public void setUp() throws Exception {
saleRespositoryMock = mock(SaleRespository.class);
saleResultRepositoryMock = mock(SaleResultRepository.class);
saleService = new SaleService(saleRespositoryMock,
saleResultRepositoryMock);
}
@Test public void generateSaleResult() throws Exception {
//given
List<Sale> sales = new ArrayList<>();
sales.add(new Sale(1l, 1l, 10000l, 1l));
given(saleRespositoryMock.findAllByProductId(productId)).willReturn(sales);
//when
saleService.generateSaleResult(productId);
//then
verify(saleRespositoryMock, times(1)).findAllByProductId(productId);
verify(saleResultRepositoryMock,times(1)).save(any(SaleResult.class));
}
Mockito
given / when / then
setUp();
List<Sale> sales = new ArrayList<>();
sales.add(new Sale(1l, 1l, 10000l, 1l));
given( saleRespositoryMock.findAllByProductId(productId) ).willReturn(sales);
saleService.generateSaleResult(productId);
verify(saleRespositoryMock, times(1) ).findAllByProductId(productId);
verify(saleResultRepositoryMock, times(1) ).save(any(SaleResult.class));
given
when
then
@Before
public void setUp() throws Exception {
saleRespositoryMock = mock(SaleRespository.class);
saleResultRepositoryMock = mock(SaleResultRepository.class);
saleService = new SaleService(saleRespositoryMock, saleResultRepositoryMock);
}
List<Sale> sales = new ArrayList<>();
sales.add(new Sale(1l, 1l, 10000l, 1l));
given( saleRespositoryMock.findAllByProductId(productId) ).willReturn(sales);
SaleService 생성자 주입
g
i
v
e
n
@Before
public void setUp() throws Exception {
saleRespositoryMock = mock(SaleRespository.class);
saleResultRepositoryMock = mock(SaleResultRepository.class);
saleService = new SaleService(saleRespositoryMock, saleResultRepositoryMock);
}
List<Sale> sales = new ArrayList<>();
sales.add(new Sale(1l, 1l, 10000l, 1l));
given( saleRespositoryMock.findAllByProductId(productId) ).willReturn(sales);
given(호출_메서드).willReturn(던져줄 값)
g
i
v
e
n
예상된 값 나오기
saleService.generateSaleResult(productId);
w
h
e
n
public void generateSaleResult(long productId) {
List<Sale> sales = saleRespository.findAllByProductId(productId);
if(sales.isEmpty()) {
throw new RuntimeException("sales is empty");
}
SaleResult saleResult = new SaleResult(productId);
saleResult.calculate(sales);
saleResultRepository.save(saleResult);
}
예상된 값 나오기
saleService.generateSaleResult(productId);
w
h
e
n
public void generateSaleResult(long productId) {
List<Sale> sales = saleRespository.findAllByProductId(productId);
if(sales.isEmpty()) {
throw new RuntimeException("sales is empty");
}
SaleResult saleResult = new SaleResult(productId);
saleResult.calculate(sales);
saleResultRepository.save(saleResult);
}
given( saleRespositoryMock.findAllByProductId(productId) ).willReturn
(sales);
saleService.generateSaleResult
saleService.generateSaleResult(productId);
w
h
e
n
public void generateSaleResult(long productId) {
List<Sale> sales = saleRespository.findAllByProductId(productId);
if(sales.isEmpty()) {
throw new RuntimeException("sales is empty");
}
SaleResult saleResult = new SaleResult(productId);
saleResult.calculate(sales);
saleResultRepository.save(saleResult);
}
검증
verify(saleRespositoryMock, times(1)).findAllByProductId(productId);
verify(saleResultRepositoryMock, times(1)).save(any(SaleResult.class));
t
h
e
n
임의성을 제어 해보자!
임의성 제어하기
● 예 : 숫자야구 게임
● 상황
○ 숫자야구 게임 실행시 내부에서 임의로 정답을 생성
■ 단위 테스트 작성을 위해서는 개발자가 정답을 알아야
함
숫자야구 게임 정답 가져오기
class BaseBallGame
public BaseBallResult play(String number) {
int strike = 0, ball = 0;
for(int i = 0 ; i < getNumber().length() ; i ++ ) {
//strike, ball 구하는 구현체
if( getNumber().charAt(i) == number.charAt(j)) {
…..
}
}
return new BaseBallResult(strike,ball);
}
private String getNumber() {
List<String> numbers = Lists.newArrayList("1", "2", "3", "4",
"5", "6", "7", "8", "9");
Random random = new Random(System.nanoTime());
Collections.shuffle(numbers, random);
return numbers.get(0) + numbers.get(1) + numbers.get(2);
}
AS - IS
숫자야구 게임 정답 가져오기
class BaseBallGame
public BaseBallResult play(String number) {
int strike = 0, ball = 0;
for(int i = 0 ; i < getNumber().length() ; i ++ ) {
//strike, ball 구하는 구현체
if( getNumber().charAt(i) == number.charAt(j)) {
…..
}
}
return new BaseBallResult(strike,ball);
}
private String getNumber() {
List<String> numbers = Lists.newArrayList("1", "2", "3", "4",
"5", "6", "7", "8", "9");
Random random = new Random(System.nanoTime());
Collections.shuffle(numbers, random);
return numbers.get(0) + numbers.get(1) + numbers.get(2);
}
AS - IS
getNumber()를 원하
는 값이 나오게 할 수
가 없네..
숫자야구 게임 정답 가져오기
class BaseBallGame
public BaseBallResult play(String number) {
int strike = 0, ball = 0;
for(int i = 0 ; i < getNumber().length() ; i ++ ) {
//strike, ball 구하는 구현체
if( getNumber().charAt(i) == number.charAt(j)) {
…..
}
}
return new BaseBallResult(strike,ball);
}
private String getNumber() {
List<String> numbers = Lists.newArrayList("1", "2", "3", "4",
"5", "6", "7", "8", "9");
Random random = new Random(System.nanoTime());
Collections.shuffle(numbers, random);
return numbers.get(0) + numbers.get(1) + numbers.get(2);
}
AS - IS 테스트 할 수가 없어..
http://www.freeimages.com/photo/776061
숫자야구 게임 정답 가져오기
BaseBallGame
<<interface>>
BaseBallNumber
1
1
● 해결책 ?
○ 정답을 만들어주는 녀석을 인터페이스로 주입받아서 처리하자
RandomBaseBallNumber
숫자야구 게임 정답 가져오기
class BaseBallGame
private BaseBallNumber baseballNumber;
public void setBaseBallNumber(baseballNumber) {
this.baseballNumber = baseballNumber;
}
public BaseBallResult play(String number) {
...
if( getNumber().charAt(i) == number.charAt(j)) {
…..
}
….
return new BaseBallResult(strike,ball);
}
private String getNumber() {
return baseballNumber.getNumber();
}
TO - BE
숫자야구 게임 정답 가져오기
class BaseBallGame
private BaseBallNumber baseballNumber;
public void setBaseBallNumber(baseballNumber) {
this.baseballNumber = baseballNumber;
}
public BaseBallResult play(String number) {
...
if( getNumber().charAt(i) == number.charAt(j)) {
…..
}
….
return new BaseBallResult(strike,ball);
}
class BaseBallGameTest
BaseBallGame game;
//setUp에서 game 생성
@Test public void givenNumber_assertBaseBall() {
baseBallNumber = new BaseBallNumber(){
@Override public String getNumber() {
return "123";
}
};
game.setBaseBallNumber(baseBallNumber);
//검증 ..
}
TO - BE
좋은 정보
숫자야구게임 TDD
- 최범균
http://www.youtube.com/watch?
v=960hX13PDuk
테스트 작성 흐름
실패한 테스트
작성
테스트 성공
리팩토링
자, 이제부터 단위테스트를
작성해보아요 ^_^
참조
● Effective Unit Testing - 라쎄 코스켈라
● UnitTest by Martin Fowler
○ http://martinfowler.com/bliki/UnitTest.html
● 숫자야구게임 TDD - 최범균
○ http://www.youtube.com/watch?v=960hX13PDuk
● TDD Live (springcamp2013) - 최범균
○ http://www.slideshare.net/madvirus/tdd-live-spring-camp-2013?qid=8c55f248-4151-42e9-
977a-5ca334e0eabb&v=default&b=&from_search=1
● 유닛테스트 - 위키백과
○ http://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%9B_%ED%85%8C%EC%8A%A4%
ED%8A%B8
● 의존성 주입 - 위키백과
○ http://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EC%84%B1_%EC%A3%BC%
EC%9E%85
Q&A
(email : choiye84@gmail.com)
THANKS
Maldives 팀
최범균님
박용권님
양완수님

More Related Content

What's hot

Designing APIs and Microservices Using Domain-Driven Design
Designing APIs and Microservices Using Domain-Driven DesignDesigning APIs and Microservices Using Domain-Driven Design
Designing APIs and Microservices Using Domain-Driven DesignLaunchAny
 
마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017
마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017
마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017Amazon Web Services Korea
 
New features of Minimal APIs in .NET 7 -Muralidharan Deenathayalan.pptx
New features of Minimal APIs in .NET 7 -Muralidharan Deenathayalan.pptxNew features of Minimal APIs in .NET 7 -Muralidharan Deenathayalan.pptx
New features of Minimal APIs in .NET 7 -Muralidharan Deenathayalan.pptxMuralidharan Deenathayalan
 
효과적인 NoSQL (Elasticahe / DynamoDB) 디자인 및 활용 방안 (최유정 & 최홍식, AWS 솔루션즈 아키텍트) :: ...
효과적인 NoSQL (Elasticahe / DynamoDB) 디자인 및 활용 방안 (최유정 & 최홍식, AWS 솔루션즈 아키텍트) :: ...효과적인 NoSQL (Elasticahe / DynamoDB) 디자인 및 활용 방안 (최유정 & 최홍식, AWS 솔루션즈 아키텍트) :: ...
효과적인 NoSQL (Elasticahe / DynamoDB) 디자인 및 활용 방안 (최유정 & 최홍식, AWS 솔루션즈 아키텍트) :: ...Amazon Web Services Korea
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1José Paumard
 
Microservices
MicroservicesMicroservices
MicroservicesSmartBear
 
AWS 기반 대규모 트래픽 견디기 - 장준엽 (구로디지털 모임) :: AWS Community Day 2017
AWS 기반 대규모 트래픽 견디기 - 장준엽 (구로디지털 모임) :: AWS Community Day 2017AWS 기반 대규모 트래픽 견디기 - 장준엽 (구로디지털 모임) :: AWS Community Day 2017
AWS 기반 대규모 트래픽 견디기 - 장준엽 (구로디지털 모임) :: AWS Community Day 2017AWSKRUG - AWS한국사용자모임
 
AWS 를 활용한 저지연 라이브 (Low Latency Live) 서비스 구현 - 류재춘 컨설턴트/에반젤리스트, GS Neot다 :: AW...
AWS 를 활용한 저지연 라이브 (Low Latency Live) 서비스 구현 - 류재춘 컨설턴트/에반젤리스트, GS Neot다 :: AW...AWS 를 활용한 저지연 라이브 (Low Latency Live) 서비스 구현 - 류재춘 컨설턴트/에반젤리스트, GS Neot다 :: AW...
AWS 를 활용한 저지연 라이브 (Low Latency Live) 서비스 구현 - 류재춘 컨설턴트/에반젤리스트, GS Neot다 :: AW...Amazon Web Services Korea
 
AWS 기반 클라우드 아키텍처 모범사례 - 삼성전자 개발자 포털/개발자 워크스페이스 - 정영준 솔루션즈 아키텍트, AWS / 유현성 수석,...
AWS 기반 클라우드 아키텍처 모범사례 - 삼성전자 개발자 포털/개발자 워크스페이스 - 정영준 솔루션즈 아키텍트, AWS / 유현성 수석,...AWS 기반 클라우드 아키텍처 모범사례 - 삼성전자 개발자 포털/개발자 워크스페이스 - 정영준 솔루션즈 아키텍트, AWS / 유현성 수석,...
AWS 기반 클라우드 아키텍처 모범사례 - 삼성전자 개발자 포털/개발자 워크스페이스 - 정영준 솔루션즈 아키텍트, AWS / 유현성 수석,...Amazon Web Services Korea
 
DevOps Real-Time Projects | Edureka
DevOps Real-Time Projects | EdurekaDevOps Real-Time Projects | Edureka
DevOps Real-Time Projects | EdurekaEdureka!
 
Terraform modules and (some of) best practices
Terraform modules and (some of) best practicesTerraform modules and (some of) best practices
Terraform modules and (some of) best practicesAnton Babenko
 
A Pattern Language for Microservices
A Pattern Language for MicroservicesA Pattern Language for Microservices
A Pattern Language for MicroservicesChris Richardson
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean ArchitectureMattia Battiston
 
TechEvent Infrastructure as Code on Azure
TechEvent Infrastructure as Code on AzureTechEvent Infrastructure as Code on Azure
TechEvent Infrastructure as Code on AzureTrivadis
 
대용량 트래픽을 처리하는 최적의 서버리스 애플리케이션 - 안효빈, 구성완 AWS 솔루션즈 아키텍트 :: AWS Summit Seoul 2021
대용량 트래픽을 처리하는 최적의 서버리스 애플리케이션  - 안효빈, 구성완 AWS 솔루션즈 아키텍트 :: AWS Summit Seoul 2021대용량 트래픽을 처리하는 최적의 서버리스 애플리케이션  - 안효빈, 구성완 AWS 솔루션즈 아키텍트 :: AWS Summit Seoul 2021
대용량 트래픽을 처리하는 최적의 서버리스 애플리케이션 - 안효빈, 구성완 AWS 솔루션즈 아키텍트 :: AWS Summit Seoul 2021Amazon Web Services Korea
 
Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to RedisArnab Mitra
 

What's hot (20)

Designing APIs and Microservices Using Domain-Driven Design
Designing APIs and Microservices Using Domain-Driven DesignDesigning APIs and Microservices Using Domain-Driven Design
Designing APIs and Microservices Using Domain-Driven Design
 
마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017
마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017
마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017
 
Azure redis cache
Azure redis cacheAzure redis cache
Azure redis cache
 
New features of Minimal APIs in .NET 7 -Muralidharan Deenathayalan.pptx
New features of Minimal APIs in .NET 7 -Muralidharan Deenathayalan.pptxNew features of Minimal APIs in .NET 7 -Muralidharan Deenathayalan.pptx
New features of Minimal APIs in .NET 7 -Muralidharan Deenathayalan.pptx
 
효과적인 NoSQL (Elasticahe / DynamoDB) 디자인 및 활용 방안 (최유정 & 최홍식, AWS 솔루션즈 아키텍트) :: ...
효과적인 NoSQL (Elasticahe / DynamoDB) 디자인 및 활용 방안 (최유정 & 최홍식, AWS 솔루션즈 아키텍트) :: ...효과적인 NoSQL (Elasticahe / DynamoDB) 디자인 및 활용 방안 (최유정 & 최홍식, AWS 솔루션즈 아키텍트) :: ...
효과적인 NoSQL (Elasticahe / DynamoDB) 디자인 및 활용 방안 (최유정 & 최홍식, AWS 솔루션즈 아키텍트) :: ...
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1
 
Microservices
MicroservicesMicroservices
Microservices
 
AWS 기반 대규모 트래픽 견디기 - 장준엽 (구로디지털 모임) :: AWS Community Day 2017
AWS 기반 대규모 트래픽 견디기 - 장준엽 (구로디지털 모임) :: AWS Community Day 2017AWS 기반 대규모 트래픽 견디기 - 장준엽 (구로디지털 모임) :: AWS Community Day 2017
AWS 기반 대규모 트래픽 견디기 - 장준엽 (구로디지털 모임) :: AWS Community Day 2017
 
AWS 를 활용한 저지연 라이브 (Low Latency Live) 서비스 구현 - 류재춘 컨설턴트/에반젤리스트, GS Neot다 :: AW...
AWS 를 활용한 저지연 라이브 (Low Latency Live) 서비스 구현 - 류재춘 컨설턴트/에반젤리스트, GS Neot다 :: AW...AWS 를 활용한 저지연 라이브 (Low Latency Live) 서비스 구현 - 류재춘 컨설턴트/에반젤리스트, GS Neot다 :: AW...
AWS 를 활용한 저지연 라이브 (Low Latency Live) 서비스 구현 - 류재춘 컨설턴트/에반젤리스트, GS Neot다 :: AW...
 
AWS 기반 클라우드 아키텍처 모범사례 - 삼성전자 개발자 포털/개발자 워크스페이스 - 정영준 솔루션즈 아키텍트, AWS / 유현성 수석,...
AWS 기반 클라우드 아키텍처 모범사례 - 삼성전자 개발자 포털/개발자 워크스페이스 - 정영준 솔루션즈 아키텍트, AWS / 유현성 수석,...AWS 기반 클라우드 아키텍처 모범사례 - 삼성전자 개발자 포털/개발자 워크스페이스 - 정영준 솔루션즈 아키텍트, AWS / 유현성 수석,...
AWS 기반 클라우드 아키텍처 모범사례 - 삼성전자 개발자 포털/개발자 워크스페이스 - 정영준 솔루션즈 아키텍트, AWS / 유현성 수석,...
 
DevOps Real-Time Projects | Edureka
DevOps Real-Time Projects | EdurekaDevOps Real-Time Projects | Edureka
DevOps Real-Time Projects | Edureka
 
Terraform modules and (some of) best practices
Terraform modules and (some of) best practicesTerraform modules and (some of) best practices
Terraform modules and (some of) best practices
 
A Pattern Language for Microservices
A Pattern Language for MicroservicesA Pattern Language for Microservices
A Pattern Language for Microservices
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
 
React js
React jsReact js
React js
 
TechEvent Infrastructure as Code on Azure
TechEvent Infrastructure as Code on AzureTechEvent Infrastructure as Code on Azure
TechEvent Infrastructure as Code on Azure
 
대용량 트래픽을 처리하는 최적의 서버리스 애플리케이션 - 안효빈, 구성완 AWS 솔루션즈 아키텍트 :: AWS Summit Seoul 2021
대용량 트래픽을 처리하는 최적의 서버리스 애플리케이션  - 안효빈, 구성완 AWS 솔루션즈 아키텍트 :: AWS Summit Seoul 2021대용량 트래픽을 처리하는 최적의 서버리스 애플리케이션  - 안효빈, 구성완 AWS 솔루션즈 아키텍트 :: AWS Summit Seoul 2021
대용량 트래픽을 처리하는 최적의 서버리스 애플리케이션 - 안효빈, 구성완 AWS 솔루션즈 아키텍트 :: AWS Summit Seoul 2021
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
An Introduction To REST API
An Introduction To REST APIAn Introduction To REST API
An Introduction To REST API
 
Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to Redis
 

Similar to 시작하자 단위테스트

[고급과정] 코드 테스트와 커버리지 교육(실습위주)
[고급과정] 코드 테스트와 커버리지 교육(실습위주)[고급과정] 코드 테스트와 커버리지 교육(실습위주)
[고급과정] 코드 테스트와 커버리지 교육(실습위주)SangIn Choung
 
10장 결과 검증
10장 결과 검증10장 결과 검증
10장 결과 검증dagri82
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블YongEun Choi
 
Sonarqube 20160509
Sonarqube 20160509Sonarqube 20160509
Sonarqube 20160509영석 조
 
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)Suwon Chae
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental systemJaehoon Oh
 
[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개Jong Pil Won
 
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It종빈 오
 
TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기Wonchang Song
 
TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDSuwon Chae
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례SangIn Choung
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기Heo Seungwook
 
Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018KyungHo Jung
 
구글테스트
구글테스트구글테스트
구글테스트진화 손
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Ryan Park
 
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 SangIn Choung
 
테스트자동화 성공전략
테스트자동화 성공전략테스트자동화 성공전략
테스트자동화 성공전략SangIn Choung
 
The roadtocodecraft
The roadtocodecraftThe roadtocodecraft
The roadtocodecraftbbongcsu
 

Similar to 시작하자 단위테스트 (20)

[고급과정] 코드 테스트와 커버리지 교육(실습위주)
[고급과정] 코드 테스트와 커버리지 교육(실습위주)[고급과정] 코드 테스트와 커버리지 교육(실습위주)
[고급과정] 코드 테스트와 커버리지 교육(실습위주)
 
10장 결과 검증
10장 결과 검증10장 결과 검증
10장 결과 검증
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블
 
Tdd 4장
Tdd 4장Tdd 4장
Tdd 4장
 
Sonarqube 20160509
Sonarqube 20160509Sonarqube 20160509
Sonarqube 20160509
 
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개
 
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
 
TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기TDD.JUnit.조금더.알기
TDD.JUnit.조금더.알기
 
TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDD
 
테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례
 
Android unit testing
Android unit testingAndroid unit testing
Android unit testing
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 
Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018
 
구글테스트
구글테스트구글테스트
구글테스트
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005
 
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
 
테스트자동화 성공전략
테스트자동화 성공전략테스트자동화 성공전략
테스트자동화 성공전략
 
The roadtocodecraft
The roadtocodecraftThe roadtocodecraft
The roadtocodecraft
 

시작하자 단위테스트

  • 3. 사전적 의미 1) 제품의 성능이나 상태 따위를 일정한 기준에 따라 검사함 2) 일정한 기준에 따라 검사하다. 1) 사물의 길이, 넓이, 무게 등을 수치로 나타낼 때, 기본이 되는 기준 2) 하나의 집단 조직 등을 구성하는 기본적인 한덩어리. 단위 테스트 출처 : Daum 사전
  • 4. 위키백과 유닛 테스트(unit test) 컴퓨터 프로그래밍에서 소스코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검 증하는 절차다. 즉, 모든 함수와 메소드에 대한 테스트 케이스를 작성하는 절차를 말한다. …..
  • 5. 그림으로 보면.. 출처 : http://martinfowler.com/bliki/UnitTest.html
  • 8. 단위테스트를 작성하지 않은 이유 ? ● 단위테스트가 무엇인지 모른다. ● 들어봤지만, 주변에 작성하는 사람이 없다. ● 작성하고자 하지만, 너무 어렵다. ○ 어디서 어떻게 시작해야할지 모르겠다. ● 작성할 줄 알지만, ○ 귀찮다. -> 습관을 들여야한다... ○ 필요 없다. -> 천재...
  • 9. 오 해 기능 추가 시간이 너~ 무 오래 걸린다.
  • 10. 오 해 기능 추가 시간이 너~ 무 오래 걸린다. 테스트 코드량이 많아져서, 별로...
  • 11. 오 해 기능 추가 시간이 너~ 무 오래 걸린다. 테스트 코드량이 많아져서, 별로... 단위 테스트만 작성하면 버그 따윈 없어!
  • 13. 단위 테스트를 도와 주는 도구 for JAVA ● JUnit ○ (자바) 단위 테스트 프레임워크의 표준 ○ http://junit.org/ ● Mocking Framework ○ Mockito ○ easyMock ○ JMock ○ ...
  • 17. 예 : 상품 판매 금액/수량 계산하기 class SaleResult private final long productId; private long totalSalePrice; private long totalSaleCount; public SaleResult(long productId) { this.productId = productId; } public void calculate(List<Sale> sales) { for( Sale sale : sales ) { totalSalePrice += sale.getSalePrice(); totalSaleCount += sale.getSaleCount(); } } // getter/setter 생략 class Sale private long id; private long productId; private long salePrice; private long saleCount; public Sale(long id, long productId, long salePrice, long saleCount) { this.id = id; this.productId = productId; this.salePrice = salePrice; this.saleCount = saleCount; } // getter/setter 생략
  • 18. SaleResult 테스트 class SaleResult private final long productId; private long totalSalePrice; private long totalSaleCount; public SaleResult(long productId) { this.productId = productId; } public void calculate(List<Sale> sales) { for( Sale sale : sales ) { totalSalePrice += sale.getSalePrice(); totalSaleCount += sale.getSaleCount(); } } // getter/setter 생략 class SaleResultTest @Test public void calculate() throws Exception { //given long productId = 1l; List<Sale> sales = new ArrayList<>(); sales.add(new Sale(1l, 1l, 10000l, 1l)); sales.add(new Sale(2l, 1l, 10000l, 1l)); SaleResult saleResult = new SaleResult(productId); //when saleResult.calculate(sales); //then assertThat(saleResult.getTotalSalePrice(), is(20000l)); assertThat(saleResult.getTotalSaleCount(), is (2l)); }
  • 19. given / when / then long productId = 1l; List<Sale> sales = new ArrayList<>(); sales.add(new Sale(1l, 1l, 10000l, 1l)); sales.add(new Sale(2l, 1l, 10000l, 1l)); SaleResult saleResult = new SaleResult(productId); saleResult.calculate(sales); assertThat(saleResult.getTotalSalePrice(), is(20000l)); assertThat(saleResult.getTotalSaleCount(), is (2l)); given when then
  • 20. long productId = 1l; List<Sale> sales = new ArrayList<>(); sales.add(new Sale(1l, 1l, 10000l, 1l)); sales.add(new Sale(2l, 1l, 10000l, 1l)); SaleResult saleResult = new SaleResult(productId); 예상하기 (준비하기) g i v e n productId 1 totalSalePrice 0 totalSaleCount 0 SaleResult
  • 21. 실행하기 saleResult.calculate(sales); w h e n public void calculate(List<Sale> sales) { for( Sale sale : sales ) { totalSalePrice += sale.getSalePrice(); totalSaleCount += sale.getSaleCount(); } } productId 1 totalSalePrice 20000 totalSaleCount 2 SaleResult
  • 22. 검증하기 assertThat(saleResult.getTotalSalePrice(), is(20000l)); assertThat(saleResult.getTotalSaleCount(), is (2l)); t h e n productId 1 totalSalePrice 20000 totalSaleCount 2 SaleResult
  • 25. 단위테스트가 어려운 이유들.. ● 소프트웨어는 객체들이 얽히고, 설켜서, 복잡하다. ● 제어하기 힘든 것들 ○ 영속성(Persistency) ○ 시간(Time) ○ 임의성(Randomness) ○ 네트워크(Network) ○ 인프라(Infra) ○ ...
  • 26. 테스트 더블 진짜 협 력 객체 테스트 더블 테스트 더블 테스트 더블 출처 : Effective Unit Testing 테스트 대상 코드와 협력 객체를 분리 ● 테스트 작성 시 테스트 대상 코드와 상호작용하는 객체 테스트 대상 코드
  • 27. 테스트 더블 종류 스파이 객체스텁 객체 페이크 객체 목 객체 테스트 더블 출처 : Effective Unit Testing
  • 28. 테스트 더블 사용하기 ● 테스트 대상 코드에서 어떻게 테스트 더블을 사용하 지?
  • 29. 테스트 더블 사용하기 ● 테스트 대상 코드에서 어떻게 테스트 더블을 사용하 지? ○ 의존성 주입 (Dependency Injection, DI) ■ 객체간 종속성을 소스코드에서 설정하지 않고, 외부에서 주입하도록 하는 디자인 패턴 중 하나
  • 30. 테스트 더블 사용하기 ● 의존성 주입 (Dependency Injection, DI) ○ 적용 유형 ■ 생성자 주입 ■ 세터(Setter)를 통한 주입 ■ 인터페이스(Interface)를 통한 주입
  • 31. 테스트 더블 사용하기 ● 의존성 주입 (Dependency Injection, DI) ○ 인터페이스를 통한 주입 <<interface>> Ram SamsungRam HynixRam MotherBoard 1 4
  • 32. 테스트 더블 사용하기 ● 의존성 주입 (Dependency Injection, DI) class MotherBoard private Ram ram; public MotherBoard(Ram ram) { this.ram = ram; } // 생성자 주입 class MotherBoard private Ram ram; public void setRam(Ram ram) { this.ram = ram; } // 세터(setter) 주입 class MotherBoard Ram ram = new HynixRam(); // 안티 패턴 MotherBoard b = new MotherBoard (new SamsungRam()); MotherBoard b= new MotherBoard(); b.setRam(new HynixRam()); MotherBoard b= new MotherBoard();
  • 33. 테스트 더블을 이용해서 영속성 단위 테스트 해보자!
  • 35. 영속성에 대한 대처 SaleService SaleResult <<interface>> SaleRepository <<interface>> SaleResultRepository <<create>> 1 1 1 1 ● 상품의 판매 금액/수량을 계산 하여, DB에 저장하기 테스트 더블 진짜 협력객체 테스트 대상코드
  • 36. SaleResult 저장하기 class SaleService private final SaleRespository saleRespository; private final SaleResultRepository saleResultRepository; public SaleService(saleRespository, saleResultRepository) { this.saleRespository = saleRespository; this.saleResultRepository = saleResultRepository; } public void generateSaleResult(long productId) { List<Sale> sales = saleRespository.findAllByProductId (productId); if(sales.isEmpty()) { throw new RuntimeException("sales is empty"); } SaleResult saleResult = new SaleResult(productId); saleResult.calculate(sales); saleResultRepository.save(saleResult); } class SaleServiceTest @Before public void setUp() throws Exception { saleRespositoryMock = mock(SaleRespository.class); saleResultRepositoryMock = mock(SaleResultRepository.class); saleService = new SaleService(saleRespositoryMock, saleResultRepositoryMock); } @Test public void generateSaleResult() throws Exception { //given List<Sale> sales = new ArrayList<>(); sales.add(new Sale(1l, 1l, 10000l, 1l)); given(saleRespositoryMock.findAllByProductId(productId)).willReturn(sales); //when saleService.generateSaleResult(productId); //then verify(saleRespositoryMock, times(1)).findAllByProductId(productId); verify(saleResultRepositoryMock,times(1)).save(any(SaleResult.class)); }
  • 37. SaleResult 저장하기 class SaleService private final SaleRespository saleRespository; private final SaleResultRepository saleResultRepository; public SaleService(saleRespository, saleResultRepository) { this.saleRespository = saleRespository; this.saleResultRepository = saleResultRepository; } public void generateSaleResult(long productId) { List<Sale> sales = saleRespository.findAllByProductId (productId); if(sales.isEmpty()) { throw new RuntimeException("sales is empty"); } SaleResult saleResult = new SaleResult(productId); saleResult.calculate(sales); saleResultRepository.save(saleResult); } class SaleServiceTest @Before public void setUp() throws Exception { saleRespositoryMock = mock(SaleRespository.class); saleResultRepositoryMock = mock(SaleResultRepository.class); saleService = new SaleService(saleRespositoryMock, saleResultRepositoryMock); } @Test public void generateSaleResult() throws Exception { //given List<Sale> sales = new ArrayList<>(); sales.add(new Sale(1l, 1l, 10000l, 1l)); given(saleRespositoryMock.findAllByProductId(productId)).willReturn(sales); //when saleService.generateSaleResult(productId); //then verify(saleRespositoryMock, times(1)).findAllByProductId(productId); verify(saleResultRepositoryMock,times(1)).save(any(SaleResult.class)); } Mockito
  • 38. given / when / then setUp(); List<Sale> sales = new ArrayList<>(); sales.add(new Sale(1l, 1l, 10000l, 1l)); given( saleRespositoryMock.findAllByProductId(productId) ).willReturn(sales); saleService.generateSaleResult(productId); verify(saleRespositoryMock, times(1) ).findAllByProductId(productId); verify(saleResultRepositoryMock, times(1) ).save(any(SaleResult.class)); given when then
  • 39. @Before public void setUp() throws Exception { saleRespositoryMock = mock(SaleRespository.class); saleResultRepositoryMock = mock(SaleResultRepository.class); saleService = new SaleService(saleRespositoryMock, saleResultRepositoryMock); } List<Sale> sales = new ArrayList<>(); sales.add(new Sale(1l, 1l, 10000l, 1l)); given( saleRespositoryMock.findAllByProductId(productId) ).willReturn(sales); SaleService 생성자 주입 g i v e n
  • 40. @Before public void setUp() throws Exception { saleRespositoryMock = mock(SaleRespository.class); saleResultRepositoryMock = mock(SaleResultRepository.class); saleService = new SaleService(saleRespositoryMock, saleResultRepositoryMock); } List<Sale> sales = new ArrayList<>(); sales.add(new Sale(1l, 1l, 10000l, 1l)); given( saleRespositoryMock.findAllByProductId(productId) ).willReturn(sales); given(호출_메서드).willReturn(던져줄 값) g i v e n
  • 41. 예상된 값 나오기 saleService.generateSaleResult(productId); w h e n public void generateSaleResult(long productId) { List<Sale> sales = saleRespository.findAllByProductId(productId); if(sales.isEmpty()) { throw new RuntimeException("sales is empty"); } SaleResult saleResult = new SaleResult(productId); saleResult.calculate(sales); saleResultRepository.save(saleResult); }
  • 42. 예상된 값 나오기 saleService.generateSaleResult(productId); w h e n public void generateSaleResult(long productId) { List<Sale> sales = saleRespository.findAllByProductId(productId); if(sales.isEmpty()) { throw new RuntimeException("sales is empty"); } SaleResult saleResult = new SaleResult(productId); saleResult.calculate(sales); saleResultRepository.save(saleResult); } given( saleRespositoryMock.findAllByProductId(productId) ).willReturn (sales);
  • 43. saleService.generateSaleResult saleService.generateSaleResult(productId); w h e n public void generateSaleResult(long productId) { List<Sale> sales = saleRespository.findAllByProductId(productId); if(sales.isEmpty()) { throw new RuntimeException("sales is empty"); } SaleResult saleResult = new SaleResult(productId); saleResult.calculate(sales); saleResultRepository.save(saleResult); }
  • 46. 임의성 제어하기 ● 예 : 숫자야구 게임 ● 상황 ○ 숫자야구 게임 실행시 내부에서 임의로 정답을 생성 ■ 단위 테스트 작성을 위해서는 개발자가 정답을 알아야 함
  • 47. 숫자야구 게임 정답 가져오기 class BaseBallGame public BaseBallResult play(String number) { int strike = 0, ball = 0; for(int i = 0 ; i < getNumber().length() ; i ++ ) { //strike, ball 구하는 구현체 if( getNumber().charAt(i) == number.charAt(j)) { ….. } } return new BaseBallResult(strike,ball); } private String getNumber() { List<String> numbers = Lists.newArrayList("1", "2", "3", "4", "5", "6", "7", "8", "9"); Random random = new Random(System.nanoTime()); Collections.shuffle(numbers, random); return numbers.get(0) + numbers.get(1) + numbers.get(2); } AS - IS
  • 48. 숫자야구 게임 정답 가져오기 class BaseBallGame public BaseBallResult play(String number) { int strike = 0, ball = 0; for(int i = 0 ; i < getNumber().length() ; i ++ ) { //strike, ball 구하는 구현체 if( getNumber().charAt(i) == number.charAt(j)) { ….. } } return new BaseBallResult(strike,ball); } private String getNumber() { List<String> numbers = Lists.newArrayList("1", "2", "3", "4", "5", "6", "7", "8", "9"); Random random = new Random(System.nanoTime()); Collections.shuffle(numbers, random); return numbers.get(0) + numbers.get(1) + numbers.get(2); } AS - IS getNumber()를 원하 는 값이 나오게 할 수 가 없네..
  • 49. 숫자야구 게임 정답 가져오기 class BaseBallGame public BaseBallResult play(String number) { int strike = 0, ball = 0; for(int i = 0 ; i < getNumber().length() ; i ++ ) { //strike, ball 구하는 구현체 if( getNumber().charAt(i) == number.charAt(j)) { ….. } } return new BaseBallResult(strike,ball); } private String getNumber() { List<String> numbers = Lists.newArrayList("1", "2", "3", "4", "5", "6", "7", "8", "9"); Random random = new Random(System.nanoTime()); Collections.shuffle(numbers, random); return numbers.get(0) + numbers.get(1) + numbers.get(2); } AS - IS 테스트 할 수가 없어.. http://www.freeimages.com/photo/776061
  • 50. 숫자야구 게임 정답 가져오기 BaseBallGame <<interface>> BaseBallNumber 1 1 ● 해결책 ? ○ 정답을 만들어주는 녀석을 인터페이스로 주입받아서 처리하자 RandomBaseBallNumber
  • 51. 숫자야구 게임 정답 가져오기 class BaseBallGame private BaseBallNumber baseballNumber; public void setBaseBallNumber(baseballNumber) { this.baseballNumber = baseballNumber; } public BaseBallResult play(String number) { ... if( getNumber().charAt(i) == number.charAt(j)) { ….. } …. return new BaseBallResult(strike,ball); } private String getNumber() { return baseballNumber.getNumber(); } TO - BE
  • 52. 숫자야구 게임 정답 가져오기 class BaseBallGame private BaseBallNumber baseballNumber; public void setBaseBallNumber(baseballNumber) { this.baseballNumber = baseballNumber; } public BaseBallResult play(String number) { ... if( getNumber().charAt(i) == number.charAt(j)) { ….. } …. return new BaseBallResult(strike,ball); } class BaseBallGameTest BaseBallGame game; //setUp에서 game 생성 @Test public void givenNumber_assertBaseBall() { baseBallNumber = new BaseBallNumber(){ @Override public String getNumber() { return "123"; } }; game.setBaseBallNumber(baseBallNumber); //검증 .. } TO - BE
  • 53. 좋은 정보 숫자야구게임 TDD - 최범균 http://www.youtube.com/watch? v=960hX13PDuk
  • 54. 테스트 작성 흐름 실패한 테스트 작성 테스트 성공 리팩토링
  • 56. 참조 ● Effective Unit Testing - 라쎄 코스켈라 ● UnitTest by Martin Fowler ○ http://martinfowler.com/bliki/UnitTest.html ● 숫자야구게임 TDD - 최범균 ○ http://www.youtube.com/watch?v=960hX13PDuk ● TDD Live (springcamp2013) - 최범균 ○ http://www.slideshare.net/madvirus/tdd-live-spring-camp-2013?qid=8c55f248-4151-42e9- 977a-5ca334e0eabb&v=default&b=&from_search=1 ● 유닛테스트 - 위키백과 ○ http://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%9B_%ED%85%8C%EC%8A%A4% ED%8A%B8 ● 의존성 주입 - 위키백과 ○ http://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EC%84%B1_%EC%A3%BC% EC%9E%85