3. 사전적 의미
1) 제품의 성능이나 상태 따위를 일정한 기준에 따라 검사함
2) 일정한 기준에 따라 검사하다.
1) 사물의 길이, 넓이, 무게 등을 수치로 나타낼 때, 기본이 되는 기준
2) 하나의 집단 조직 등을 구성하는 기본적인 한덩어리.
단위
테스트
출처 : Daum 사전
4. 위키백과
유닛 테스트(unit test)
컴퓨터 프로그래밍에서 소스코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검
증하는 절차다.
즉, 모든 함수와 메소드에 대한 테스트 케이스를 작성하는 절차를 말한다.
…..
8. 단위테스트를 작성하지 않은 이유 ?
● 단위테스트가 무엇인지 모른다.
● 들어봤지만, 주변에 작성하는 사람이 없다.
● 작성하고자 하지만, 너무 어렵다.
○ 어디서 어떻게 시작해야할지 모르겠다.
● 작성할 줄 알지만,
○ 귀찮다. -> 습관을 들여야한다...
○ 필요 없다. -> 천재...
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
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();
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);
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