SlideShare uma empresa Scribd logo
1 de 58
xUnit 테스트 패턴 10장 결과 검증 최기원
10장에서 이야기 하는 것 테스트 결과 검증 방법 테스트 코드 작성 노하우
10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
상태 검증 SUT의 기대 결과 값이 발생했는지 검증하는 '일반적인' 방법 3가지 방법 내장 단언문을 사용하는 방법 델타 단언문을 사용하는 방법 외부 결과 검증 방법
내장 단언문 사용 하는 방법 assertTrue(aBooleanExpression) 결과 지정 단언문 assertEquals(expected, actual) 동등 단언문 assertEquals(expected, actual, tolerance) 퍼지 동등 단언문
델타 단언문 1. 관련 테이블/클래스에 대한 일종의 '스냅샷'을 테스트 시작할 때 저장한다. 2. 테스트가 끝나면 생성된 객체/로우 집합에서 아까의 '스냅샷'을 제거한 후 남은 것들을 기대 결과 값과 비교
외부 결과 검증 예상 결과와 실제 결과를 파일로 저장한 후 외부 파일 비교 프로그램으로 차이를 확인하는 것
10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
동작 검증 SUT의 동작을 검증 하는 방법 2가지 방법 절차형 동작 검증 기대 동작 명세
절차형 동작 검증 SUT가 실행될 때 원하는 동작을 잡아낸 후 나중에 쓸 데이터를 저장해둔다. 나중에 테스트에서는 SUT의 출력 값을 해당 기대 결과 값과 하나하나 비교한다.
public void testRemoveFlightLogging_recordingTestStub() throw Exception { 	// 픽스쳐 설치 FlightDto expectedFlightDto = createAnUnregFlight(); 	FlightManagementFacade facade = new FlightManagementFacadeImpl(); 	// 테스트 대역 설치 AuditLogSpy logSpy = new AuditLogSpy(); 	facade.setAuditLog(logSpy); 	// 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); 	//검증 assertEquals("number of calls", 1,  			logSpy.getNumberofCalls()); 	assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE,  			logSpy.getActionCode()); 	assertEquals("date", helper.getTodayDateWithoutTime(),  			logSpy.getDate()); 	assertEquals("user", Helper.TEST_USER_NAME,  			logSpy.getUser()); 	assertEquals("detail", expectedFlightDto.getFlightNumber(),  			logSpy.getDetail()); }
public void testRemoveFlightLogging_recordingTestStub() throw Exception { 	// 픽스쳐 설치 FlightDto expectedFlightDto = createAnUnregFlight(); 	FlightManagementFacade facade = new FlightManagementFacadeImpl(); 	// 테스트 대역 설치 AuditLogSpy logSpy = new AuditLogSpy(); 	facade.setAuditLog(logSpy); 	// 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); 	//검증 assertEquals("number of calls", 1,  			logSpy.getNumberofCalls()); 	assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE,  			logSpy.getActionCode()); 	assertEquals("date", helper.getTodayDateWithoutTime(),  			logSpy.getDate()); 	assertEquals("user", Helper.TEST_USER_NAME,  			logSpy.getUser()); 	assertEquals("detail", expectedFlightDto.getFlightNumber(),  			logSpy.getDetail()); }
public void testRemoveFlightLogging_recordingTestStub() throw Exception { 	// 픽스쳐 설치 FlightDto expectedFlightDto = createAnUnregFlight(); 	FlightManagementFacade facade = new FlightManagementFacadeImpl(); 	// 테스트 대역 설치 AuditLogSpy logSpy = new AuditLogSpy(); 	facade.setAuditLog(logSpy); 	// 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); 	//검증 assertEquals("number of calls", 1,  			logSpy.getNumberofCalls()); 	assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE,  			logSpy.getActionCode()); 	assertEquals("date", helper.getTodayDateWithoutTime(),  			logSpy.getDate()); 	assertEquals("user", Helper.TEST_USER_NAME,  			logSpy.getUser()); 	assertEquals("detail", expectedFlightDto.getFlightNumber(),  			logSpy.getDetail()); }
public void testRemoveFlightLogging_recordingTestStub() throw Exception { 	// 픽스쳐 설치 FlightDto expectedFlightDto = createAnUnregFlight(); 	FlightManagementFacade facade = new FlightManagementFacadeImpl(); 	// 테스트 대역 설치 AuditLogSpy logSpy = new AuditLogSpy(); 	facade.setAuditLog(logSpy); 	// 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); 	//검증 assertEquals("number of calls", 1,  			logSpy.getNumberofCalls()); 	assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE,  			logSpy.getActionCode()); 	assertEquals("date", helper.getTodayDateWithoutTime(),  			logSpy.getDate()); 	assertEquals("user", Helper.TEST_USER_NAME,  			logSpy.getUser()); 	assertEquals("detail", expectedFlightDto.getFlightNumber(),  			logSpy.getDetail()); }
기대 동작 명세 상태를 검증하기 위해 기대 객체를 생성해 SUT가 리턴하는 실제 객체와 비교 한다.
public void testRemoveFlight_JMock() throws Exception { 	// 픽스쳐 설치 FlightDto expectedFlightDto = createAnonRegFlight(); 	FlightManagementFacade facade = new FlightManagementFacadeImpl(); 	// 모의 객체 설정 Mock mockLog = mock(AuditLog.class); 	mockLog.expects(once()).method("logMessage") 			.with(eq(Helper.getTodaysDateWithoutTime()), 				eq(Helper.TEST_USER_NAME), 				eq(Helper.REMOVE_FLIGHT_ACTION_CODE), 				eq(expectedFlightDto.getFlightNumber())); 	// 모의 객체 설치 facade.setAuditLog((AuditLog)mockLog.proxy()); 	// 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); 	// 검증 // verify() 메소드는 JMock에 의해 자동으로 호출된다. }
public void testRemoveFlight_JMock() throws Exception { 	// 픽스쳐 설치 FlightDto expectedFlightDto = createAnonRegFlight(); 	FlightManagementFacade facade = new FlightManagementFacadeImpl(); 	// 모의 객체 설정 Mock mockLog = mock(AuditLog.class); 	mockLog.expects(once()).method("logMessage") 			.with(eq(Helper.getTodaysDateWithoutTime()), 				eq(Helper.TEST_USER_NAME), 				eq(Helper.REMOVE_FLIGHT_ACTION_CODE), 				eq(expectedFlightDto.getFlightNumber())); 	// 모의 객체 설치 facade.setAuditLog((AuditLog)mockLog.proxy()); 	// 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); 	// 검증 // verify() 메소드는 JMock에 의해 자동으로 호출된다. }
public void testRemoveFlight_JMock() throws Exception { 	// 픽스쳐 설치 FlightDto expectedFlightDto = createAnonRegFlight(); 	FlightManagementFacade facade = new FlightManagementFacadeImpl(); 	// 모의 객체 설정 Mock mockLog = mock(AuditLog.class); 	mockLog.expects(once()).method("logMessage") 			.with(eq(Helper.getTodaysDateWithoutTime()), 				eq(Helper.TEST_USER_NAME), 				eq(Helper.REMOVE_FLIGHT_ACTION_CODE), 				eq(expectedFlightDto.getFlightNumber())); 	// 모의 객체 설치 facade.setAuditLog((AuditLog)mockLog.proxy()); 	// 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); 	// 검증 // verify() 메소드는 JMock에 의해 자동으로 호출된다. }
10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
테스트 코드가 중복이 되면 생기는 문제점 깨지기 쉬운 테스트 깨지기 쉬운 픽스쳐 높은 테스트 유지 비용 테스트의 의도가 애매해짐
코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
같은 객체의 다른 필드 값을 여러 개 검증할때, 전체적으로 한 줄에 서로 비교할 수 있는 동등 단언문을 사용하는 것
public void testInvoice_addLineItem7() { 	LineItem expItem = new LineItem(inv, product, QUANTITY); 	// 실행 inv.addItemQuantity(product, QUANTITY); 	// 검증 List lineItems = inv.getLineItems(); 	LineItem actual = (LineItem)lineItems.get(0); 	assertEquals(expItem.getInv(), actual.getInv()); 	assertEquals(expItem.getProd(), actual.getProd)()); 	assertEquals(expItem.getQuantity(), actual.getQuantity()); }
public void testInvoice_addLineItem8() { 	LineItem expItem = new LineItem(inv, product, QUANTITY); 	// 실행 inv.addItemQuantity(product, QUANTITY); 	// 검증 List lineItems = inv.getLineItems(); 	LineItem actual = (LineItem)lineItems.get(0); 	assertEquals("Item", expItem, actual); }
코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
static void assertLineItemsEqual(String msg,                                                       LineItem exp,                                                       LineItem act) { 	assertEquals(msg+" Inv", exp.getInv(), act.getInv()); 	assertEquals(msg+" Prod", exp.getProd(), act.getProd()); 	assertEquals(msg+" Quan", exp.getQuantity(), act.getQuantity()); }
public void testInvoice_addLineItem8() { 	LineItem expItem = new LineItem(inv, product, QUANTITY); 	// 실행 inv.addItemQuantity(product, QUANTITY); 	// 검증 List lineItems = inv.getLineItems(); 	LineItem actual = (LineItem)lineItems.get(0); 	 assertLineItemsEqual ("Item", expItem, actual); }
맞춤 단언문을 만드는 요령 먼저 비어있는 단언 메소드를 호출하게 테스트 작성후 맞춤 단언문이 파악되면 적당한 로직을 채운다
맞춤 단언문의 장점 결과 검증 절차를 알기 쉬운 이름으로 숨긴다. 의도가 눈에 잘 들어온다. 단언문 로직도 맞춤 단언문 테스트를 작성해 단위 테스트 할 수 있다. 맞춤 단언문이 필요할때 모든 필드를 비교하고 싶지 않을때 동등 대신 동일만 비교하고 싶을때 테스트용 동등을 원할때 생성자가 없어 기대 객체의 인스턴스를 생성할 수 없을때
코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
void assertInvoiceContainsOnlyThisLineItem(Invoice inv,                                                                          LineItem expItem) { 	List lineItems = inv.getLineItems(); 	assertEquals("number of items", lineItems.size(), 1); 	LineItem actual = (LineItem)lineItems.get(0); 	assertLineItemsEqual("", expItem, actual); }
검증 메소드와 맞춤 단언문 차이 맞춤 단언문은 단언만 하는 데 반해 검증 메소드는 SUT와 상호작용도 한다. 맞춤 단언문의 시그니처는 일반적인 동등 단언문 시그니처 검증 메소드에서는 SUT에 넘겨줄 추가 인자가 필요해서 형태가 자유롭다. 본질적으로 검증 메소드는 맞춤 단언문과 인자를 받는 테스트의 중간 형태
코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
픽스처 설치 로직이 똑같고 데이터만 다를 경우 공통의 픽스처 설치, SUT 실행 , 결과 검증 부분만을 뽑아서 만든다. 픽스처 설치, SUT 실행, 기대 결과에 필요한 데이터가 포함돼 있다.
def tset_extref 	sourceXml = "<extref id='abc' />" 	expectedHtml = "<a href='abc.html'>abc</a>" 	generateAndVerifyHtml(sourceXml,expectedHtml,"<extref>") end def test_testterm_normal 	sourceXml = "<testterm id='abc'/>" 	expectedHtml = "<a href='abc.html'>abc</a>" 	generateAndVerifyHtml(sourceXml,expectedHtml,"<testterm>") end def test_testterm_plural 	sourceXml = "<testterm id='abc'/>" 	expectedHtml = "<a href='abc.html'>abcs</a>" 	generateAndVerifyHtml(sourceXml,expectedHtml,"<plural>") end
코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
데이터 주도 테스트 테스트 케이스는 일반적이며 프레임워크가 직접 실행할 수 있다. 실행될 때는 테스트 데이터 파일에서 인자를 읽어온다. 인자를 받는 테스트는 테스트용 데이터를 테스트 메소드에서 받는 반면에 데이터 주도 테스트는 자체가 테스트 메소드이고 파일에서 테스트용 데이터를 직접 읽어 들인다.
Data File ID, Action, SourceXml, ExpectedHtml Extref,crossref,<extref id='abc'/>,<a href='abc.html'>abc</a> TTerm,crossref,<testterm id='abc'/>,<a href='abc.html'>abc</a> TTerms,crossref,<testterms id='abc'/>,<a href='abc.html'>abcs</a> def executeDataDrivenTest filename 	dataFile = File.open(filename) 	dataFile.each_line do | line | 		desc, action, part2 = line.split(",") 		sourceXml, expectedHtml, leftOver = part2.split(",") 		if "crossref"==action.strip 			generateAndVerifyHtml sourceXml, expectedHtml, desc 		else # 새 '동사'들은 위에 elseif 형태로 추가할 수 있다. 			report_error("unknown action" + action.strip) 		end 	end end
10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
테스트 내에 조건문이 있으면  같은 테스트가 상황에 따라 다르게 실행될 수 있다는 점에서 나쁘다. 신뢰가 떨어진다.
조건문을 넣는 이유 테스트 도중 이미 잘못된 부분을 찾았다면 나머지 단언문은 실행해봐야 별 도움이 안 되니까 아예 실행하고 싶지 않다. 코드가 읽기 어려워진다. 기대 결과 값과 비교하는 실제 결과에 대해 다양한 상황을 허용해야 한다. 코드가 읽기 어려워진다. 하나의 테스트 메소드를 여러 상황에서 재사용하고 싶다. 절대 하지마
if문 제거하기 보호 단언문을 쓴다.테스트 내 조건문 로직이 없어도 테스트 에러를 낼 수 있는 곳에 단언문이 걸리게 할 수 있다.
List lineItems = invoice.getLineItems(); if (lineItems.size() == 1) { 	LineItem expected = new LineItem(invoice, product, 5,                    new BigDecimal("30"),                    new BigDecimal("69.96")); 	LineItem actItem = (LineItem) lineItems.get(0);	 	assertEquals("invoice", expected, actItem); } else { 	fail("invoice should have exactly one line item"); }
List lineItems = invoice.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem expected = new LineItem(invoice, product, 5,                         new BigDecimal("30"),                         new BigDecimal("69.96")); LineItem actItem = (LineItem) lineItems.get(0); assertEquals("invoice", expected, actItem);
반복문 제거하기 테스트 메소드에 반복문이 들어가면 다음과 같은 문제가 생긴다. 테스트할 수 없는 테스트 코드가 추가되는 셈이 된다. 애매한 테스트가 되기 쉽다. 복잡하다. 테스트를 안쓰게 된다. 해결법 테스트 유틸리티 메소드에 로직을 옮겨놓고 의도가 잘 드러나게 이름을 정하면 된다.
10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
함수의 가장 마지막 줄을 먼저 작성해본다. 테스트를 먼저 작성해 본다. 단언문들을 먼저 작성한다. 변수를 먼저 사용하고, 나중에 선언한다.
이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
일정한 추상수준을 유지하는 것을 의미 테스트 유틸리티 메소드를 호출하는 방식으로 코딩을 함으로써 테스트 메소드를 작성하는 동안에는 SUT의 요구 사항에만 집중하게 한다. 어떤 객체나 결과가 필요한지만 작성해둔다. 정의하지 않은 채로 먼저 사용하는 유틸리티 메소드는 테스트 자동 로직이 들어갈 장소 역할을 하게 된다. 테스트 유틸리티 메소드를 나중에 구현한다.
이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
테스트 유틸리티 메소드를 구현할 시점 테스트 유틸리티 메소드를 사용하는 테스트 메소드 작성이 끝났을때 테스트 유틸리티 메소드를 작성할때 테스트 유틸리티용 테스트를 작성한다.
이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
재사용 가능한 테스트 로직은 어디에 둬야 할까? 테스트 케이스 클래스 안 테스트케이스 상위클래스 테스트 도우미 안
끝

Mais conteúdo relacionado

Mais procurados

C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
Heo Seungwook
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블
YongEun Choi
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
OnGameServer
 
Agile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And HowAgile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And How
Ryan Park
 
120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장
tedypicker
 
xUnitTestPattern/chapter7
xUnitTestPattern/chapter7xUnitTestPattern/chapter7
xUnitTestPattern/chapter7
종빈 오
 

Mais procurados (20)

C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 
Python Unittest
Python UnittestPython Unittest
Python Unittest
 
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
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 
[고급과정] 코드 테스트와 커버리지 교육(실습위주)
[고급과정] 코드 테스트와 커버리지 교육(실습위주)[고급과정] 코드 테스트와 커버리지 교육(실습위주)
[고급과정] 코드 테스트와 커버리지 교육(실습위주)
 
Agile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And HowAgile Test Driven Development For Games What, Why, And How
Agile Test Driven Development For Games What, Why, And How
 
Check style 기초가이드
Check style 기초가이드Check style 기초가이드
Check style 기초가이드
 
120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장
 
아해2019 SpringAOP 문겸
아해2019 SpringAOP 문겸아해2019 SpringAOP 문겸
아해2019 SpringAOP 문겸
 
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
 
xUnitTestPattern/chapter7
xUnitTestPattern/chapter7xUnitTestPattern/chapter7
xUnitTestPattern/chapter7
 
Android unit testing
Android unit testingAndroid unit testing
Android unit testing
 
6 function
6 function6 function
6 function
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005
 
Javascript기초
Javascript기초Javascript기초
Javascript기초
 
Legacy code refactoring video rental system
Legacy code refactoring   video rental systemLegacy code refactoring   video rental system
Legacy code refactoring video rental system
 
[Main Session] 미래의 Java 미리보기 - 앰버와 발할라 프로젝트를 중심으로
[Main Session] 미래의 Java 미리보기 - 앰버와 발할라 프로젝트를 중심으로[Main Session] 미래의 Java 미리보기 - 앰버와 발할라 프로젝트를 중심으로
[Main Session] 미래의 Java 미리보기 - 앰버와 발할라 프로젝트를 중심으로
 
Deview 2019 눈발자국
Deview 2019 눈발자국Deview 2019 눈발자국
Deview 2019 눈발자국
 

Semelhante a 10장 결과 검증

데이터베이스패턴
데이터베이스패턴데이터베이스패턴
데이터베이스패턴
Suan Lee
 
Naver api for android
Naver api for androidNaver api for android
Naver api for android
Sangon Lee
 
TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDD
Suwon Chae
 
프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가
홍준 김
 
Spring test mvc 발표자료
Spring test mvc 발표자료Spring test mvc 발표자료
Spring test mvc 발표자료
수홍 이
 
Xunittestpatternchapter11
Xunittestpatternchapter11Xunittestpatternchapter11
Xunittestpatternchapter11
duaa83
 

Semelhante a 10장 결과 검증 (20)

테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례테스터가 말하는 테스트코드 작성 팁과 사례
테스터가 말하는 테스트코드 작성 팁과 사례
 
데이터베이스패턴
데이터베이스패턴데이터베이스패턴
데이터베이스패턴
 
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
 
Sonarqube 20160509
Sonarqube 20160509Sonarqube 20160509
Sonarqube 20160509
 
JUnit & AssertJ
JUnit & AssertJJUnit & AssertJ
JUnit & AssertJ
 
[OKKY 세미나] 정진욱 - 테스트하기 쉬운 코드로 개발하기
[OKKY 세미나] 정진욱 - 테스트하기 쉬운 코드로 개발하기[OKKY 세미나] 정진욱 - 테스트하기 쉬운 코드로 개발하기
[OKKY 세미나] 정진욱 - 테스트하기 쉬운 코드로 개발하기
 
[방송통신대 컴퓨터과학과] C++ 프로그래밍 과제물 작성
[방송통신대 컴퓨터과학과] C++ 프로그래밍 과제물 작성[방송통신대 컴퓨터과학과] C++ 프로그래밍 과제물 작성
[방송통신대 컴퓨터과학과] C++ 프로그래밍 과제물 작성
 
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 TestOkjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
 
Naver api for android
Naver api for androidNaver api for android
Naver api for android
 
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
 
Android UI Test (Espresso/Kakao)
Android UI Test (Espresso/Kakao)Android UI Test (Espresso/Kakao)
Android UI Test (Espresso/Kakao)
 
TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDD
 
프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가프로그램은 왜 실패 하는가
프로그램은 왜 실패 하는가
 
Spring test mvc 발표자료
Spring test mvc 발표자료Spring test mvc 발표자료
Spring test mvc 발표자료
 
TDD - Test Driven Development
TDD - Test Driven DevelopmentTDD - Test Driven Development
TDD - Test Driven Development
 
Xunittestpatternchapter11
Xunittestpatternchapter11Xunittestpatternchapter11
Xunittestpatternchapter11
 
Cygnus unit test
Cygnus unit testCygnus unit test
Cygnus unit test
 
Backend Master | 3.2.1 Test - JUnit
Backend Master | 3.2.1 Test - JUnitBackend Master | 3.2.1 Test - JUnit
Backend Master | 3.2.1 Test - JUnit
 
Robot framework 을 이용한 기능 테스트 자동화
Robot framework 을 이용한 기능 테스트 자동화Robot framework 을 이용한 기능 테스트 자동화
Robot framework 을 이용한 기능 테스트 자동화
 
Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례Io t에서의 소프트웨어단위테스트_접근사례
Io t에서의 소프트웨어단위테스트_접근사례
 

Mais de dagri82 (10)

Ddd 14장
Ddd 14장Ddd 14장
Ddd 14장
 
D.D.D. 14장
D.D.D. 14장D.D.D. 14장
D.D.D. 14장
 
Mongo db 2장
Mongo db  2장Mongo db  2장
Mongo db 2장
 
It 개발자가쓴 통쾌한 인간관리 이야기
It 개발자가쓴 통쾌한 인간관리 이야기It 개발자가쓴 통쾌한 인간관리 이야기
It 개발자가쓴 통쾌한 인간관리 이야기
 
클로저
클로저클로저
클로저
 
보난자
보난자보난자
보난자
 
데브루키 스터디 발표
데브루키 스터디 발표데브루키 스터디 발표
데브루키 스터디 발표
 
데브루키 스터디 발표
데브루키 스터디 발표데브루키 스터디 발표
데브루키 스터디 발표
 
holubonpatternschapter41
holubonpatternschapter41holubonpatternschapter41
holubonpatternschapter41
 
holubonpatternschapter41
holubonpatternschapter41holubonpatternschapter41
holubonpatternschapter41
 

10장 결과 검증

  • 1. xUnit 테스트 패턴 10장 결과 검증 최기원
  • 2. 10장에서 이야기 하는 것 테스트 결과 검증 방법 테스트 코드 작성 노하우
  • 3. 10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
  • 4. 10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
  • 5. 상태 검증 SUT의 기대 결과 값이 발생했는지 검증하는 '일반적인' 방법 3가지 방법 내장 단언문을 사용하는 방법 델타 단언문을 사용하는 방법 외부 결과 검증 방법
  • 6. 내장 단언문 사용 하는 방법 assertTrue(aBooleanExpression) 결과 지정 단언문 assertEquals(expected, actual) 동등 단언문 assertEquals(expected, actual, tolerance) 퍼지 동등 단언문
  • 7. 델타 단언문 1. 관련 테이블/클래스에 대한 일종의 '스냅샷'을 테스트 시작할 때 저장한다. 2. 테스트가 끝나면 생성된 객체/로우 집합에서 아까의 '스냅샷'을 제거한 후 남은 것들을 기대 결과 값과 비교
  • 8. 외부 결과 검증 예상 결과와 실제 결과를 파일로 저장한 후 외부 파일 비교 프로그램으로 차이를 확인하는 것
  • 9. 10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
  • 10. 동작 검증 SUT의 동작을 검증 하는 방법 2가지 방법 절차형 동작 검증 기대 동작 명세
  • 11. 절차형 동작 검증 SUT가 실행될 때 원하는 동작을 잡아낸 후 나중에 쓸 데이터를 저장해둔다. 나중에 테스트에서는 SUT의 출력 값을 해당 기대 결과 값과 하나하나 비교한다.
  • 12. public void testRemoveFlightLogging_recordingTestStub() throw Exception { // 픽스쳐 설치 FlightDto expectedFlightDto = createAnUnregFlight(); FlightManagementFacade facade = new FlightManagementFacadeImpl(); // 테스트 대역 설치 AuditLogSpy logSpy = new AuditLogSpy(); facade.setAuditLog(logSpy); // 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); //검증 assertEquals("number of calls", 1, logSpy.getNumberofCalls()); assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE, logSpy.getActionCode()); assertEquals("date", helper.getTodayDateWithoutTime(), logSpy.getDate()); assertEquals("user", Helper.TEST_USER_NAME, logSpy.getUser()); assertEquals("detail", expectedFlightDto.getFlightNumber(), logSpy.getDetail()); }
  • 13. public void testRemoveFlightLogging_recordingTestStub() throw Exception { // 픽스쳐 설치 FlightDto expectedFlightDto = createAnUnregFlight(); FlightManagementFacade facade = new FlightManagementFacadeImpl(); // 테스트 대역 설치 AuditLogSpy logSpy = new AuditLogSpy(); facade.setAuditLog(logSpy); // 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); //검증 assertEquals("number of calls", 1, logSpy.getNumberofCalls()); assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE, logSpy.getActionCode()); assertEquals("date", helper.getTodayDateWithoutTime(), logSpy.getDate()); assertEquals("user", Helper.TEST_USER_NAME, logSpy.getUser()); assertEquals("detail", expectedFlightDto.getFlightNumber(), logSpy.getDetail()); }
  • 14. public void testRemoveFlightLogging_recordingTestStub() throw Exception { // 픽스쳐 설치 FlightDto expectedFlightDto = createAnUnregFlight(); FlightManagementFacade facade = new FlightManagementFacadeImpl(); // 테스트 대역 설치 AuditLogSpy logSpy = new AuditLogSpy(); facade.setAuditLog(logSpy); // 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); //검증 assertEquals("number of calls", 1, logSpy.getNumberofCalls()); assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE, logSpy.getActionCode()); assertEquals("date", helper.getTodayDateWithoutTime(), logSpy.getDate()); assertEquals("user", Helper.TEST_USER_NAME, logSpy.getUser()); assertEquals("detail", expectedFlightDto.getFlightNumber(), logSpy.getDetail()); }
  • 15. public void testRemoveFlightLogging_recordingTestStub() throw Exception { // 픽스쳐 설치 FlightDto expectedFlightDto = createAnUnregFlight(); FlightManagementFacade facade = new FlightManagementFacadeImpl(); // 테스트 대역 설치 AuditLogSpy logSpy = new AuditLogSpy(); facade.setAuditLog(logSpy); // 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); //검증 assertEquals("number of calls", 1, logSpy.getNumberofCalls()); assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE, logSpy.getActionCode()); assertEquals("date", helper.getTodayDateWithoutTime(), logSpy.getDate()); assertEquals("user", Helper.TEST_USER_NAME, logSpy.getUser()); assertEquals("detail", expectedFlightDto.getFlightNumber(), logSpy.getDetail()); }
  • 16. 기대 동작 명세 상태를 검증하기 위해 기대 객체를 생성해 SUT가 리턴하는 실제 객체와 비교 한다.
  • 17. public void testRemoveFlight_JMock() throws Exception { // 픽스쳐 설치 FlightDto expectedFlightDto = createAnonRegFlight(); FlightManagementFacade facade = new FlightManagementFacadeImpl(); // 모의 객체 설정 Mock mockLog = mock(AuditLog.class); mockLog.expects(once()).method("logMessage") .with(eq(Helper.getTodaysDateWithoutTime()), eq(Helper.TEST_USER_NAME), eq(Helper.REMOVE_FLIGHT_ACTION_CODE), eq(expectedFlightDto.getFlightNumber())); // 모의 객체 설치 facade.setAuditLog((AuditLog)mockLog.proxy()); // 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); // 검증 // verify() 메소드는 JMock에 의해 자동으로 호출된다. }
  • 18. public void testRemoveFlight_JMock() throws Exception { // 픽스쳐 설치 FlightDto expectedFlightDto = createAnonRegFlight(); FlightManagementFacade facade = new FlightManagementFacadeImpl(); // 모의 객체 설정 Mock mockLog = mock(AuditLog.class); mockLog.expects(once()).method("logMessage") .with(eq(Helper.getTodaysDateWithoutTime()), eq(Helper.TEST_USER_NAME), eq(Helper.REMOVE_FLIGHT_ACTION_CODE), eq(expectedFlightDto.getFlightNumber())); // 모의 객체 설치 facade.setAuditLog((AuditLog)mockLog.proxy()); // 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); // 검증 // verify() 메소드는 JMock에 의해 자동으로 호출된다. }
  • 19. public void testRemoveFlight_JMock() throws Exception { // 픽스쳐 설치 FlightDto expectedFlightDto = createAnonRegFlight(); FlightManagementFacade facade = new FlightManagementFacadeImpl(); // 모의 객체 설정 Mock mockLog = mock(AuditLog.class); mockLog.expects(once()).method("logMessage") .with(eq(Helper.getTodaysDateWithoutTime()), eq(Helper.TEST_USER_NAME), eq(Helper.REMOVE_FLIGHT_ACTION_CODE), eq(expectedFlightDto.getFlightNumber())); // 모의 객체 설치 facade.setAuditLog((AuditLog)mockLog.proxy()); // 실행 facade.removeFlight(expectedFlightDto.getFlightNumber()); // 검증 // verify() 메소드는 JMock에 의해 자동으로 호출된다. }
  • 20. 10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
  • 21. 테스트 코드가 중복이 되면 생기는 문제점 깨지기 쉬운 테스트 깨지기 쉬운 픽스쳐 높은 테스트 유지 비용 테스트의 의도가 애매해짐
  • 22. 코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
  • 23. 코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
  • 24. 같은 객체의 다른 필드 값을 여러 개 검증할때, 전체적으로 한 줄에 서로 비교할 수 있는 동등 단언문을 사용하는 것
  • 25. public void testInvoice_addLineItem7() { LineItem expItem = new LineItem(inv, product, QUANTITY); // 실행 inv.addItemQuantity(product, QUANTITY); // 검증 List lineItems = inv.getLineItems(); LineItem actual = (LineItem)lineItems.get(0); assertEquals(expItem.getInv(), actual.getInv()); assertEquals(expItem.getProd(), actual.getProd)()); assertEquals(expItem.getQuantity(), actual.getQuantity()); }
  • 26. public void testInvoice_addLineItem8() { LineItem expItem = new LineItem(inv, product, QUANTITY); // 실행 inv.addItemQuantity(product, QUANTITY); // 검증 List lineItems = inv.getLineItems(); LineItem actual = (LineItem)lineItems.get(0); assertEquals("Item", expItem, actual); }
  • 27. 코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
  • 28. static void assertLineItemsEqual(String msg, LineItem exp, LineItem act) { assertEquals(msg+" Inv", exp.getInv(), act.getInv()); assertEquals(msg+" Prod", exp.getProd(), act.getProd()); assertEquals(msg+" Quan", exp.getQuantity(), act.getQuantity()); }
  • 29. public void testInvoice_addLineItem8() { LineItem expItem = new LineItem(inv, product, QUANTITY); // 실행 inv.addItemQuantity(product, QUANTITY); // 검증 List lineItems = inv.getLineItems(); LineItem actual = (LineItem)lineItems.get(0); assertLineItemsEqual ("Item", expItem, actual); }
  • 30. 맞춤 단언문을 만드는 요령 먼저 비어있는 단언 메소드를 호출하게 테스트 작성후 맞춤 단언문이 파악되면 적당한 로직을 채운다
  • 31. 맞춤 단언문의 장점 결과 검증 절차를 알기 쉬운 이름으로 숨긴다. 의도가 눈에 잘 들어온다. 단언문 로직도 맞춤 단언문 테스트를 작성해 단위 테스트 할 수 있다. 맞춤 단언문이 필요할때 모든 필드를 비교하고 싶지 않을때 동등 대신 동일만 비교하고 싶을때 테스트용 동등을 원할때 생성자가 없어 기대 객체의 인스턴스를 생성할 수 없을때
  • 32. 코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
  • 33. void assertInvoiceContainsOnlyThisLineItem(Invoice inv, LineItem expItem) { List lineItems = inv.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem actual = (LineItem)lineItems.get(0); assertLineItemsEqual("", expItem, actual); }
  • 34. 검증 메소드와 맞춤 단언문 차이 맞춤 단언문은 단언만 하는 데 반해 검증 메소드는 SUT와 상호작용도 한다. 맞춤 단언문의 시그니처는 일반적인 동등 단언문 시그니처 검증 메소드에서는 SUT에 넘겨줄 추가 인자가 필요해서 형태가 자유롭다. 본질적으로 검증 메소드는 맞춤 단언문과 인자를 받는 테스트의 중간 형태
  • 35. 코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
  • 36. 픽스처 설치 로직이 똑같고 데이터만 다를 경우 공통의 픽스처 설치, SUT 실행 , 결과 검증 부분만을 뽑아서 만든다. 픽스처 설치, SUT 실행, 기대 결과에 필요한 데이터가 포함돼 있다.
  • 37. def tset_extref sourceXml = "<extref id='abc' />" expectedHtml = "<a href='abc.html'>abc</a>" generateAndVerifyHtml(sourceXml,expectedHtml,"<extref>") end def test_testterm_normal sourceXml = "<testterm id='abc'/>" expectedHtml = "<a href='abc.html'>abc</a>" generateAndVerifyHtml(sourceXml,expectedHtml,"<testterm>") end def test_testterm_plural sourceXml = "<testterm id='abc'/>" expectedHtml = "<a href='abc.html'>abcs</a>" generateAndVerifyHtml(sourceXml,expectedHtml,"<plural>") end
  • 38. 코드 중복을 줄이는 방법 기대 객체 사용 맞춤 단언문 사용 결과를 설명하는 검증 메소드 사용 인자를 받는 테스트 데이터 주도 테스트
  • 39. 데이터 주도 테스트 테스트 케이스는 일반적이며 프레임워크가 직접 실행할 수 있다. 실행될 때는 테스트 데이터 파일에서 인자를 읽어온다. 인자를 받는 테스트는 테스트용 데이터를 테스트 메소드에서 받는 반면에 데이터 주도 테스트는 자체가 테스트 메소드이고 파일에서 테스트용 데이터를 직접 읽어 들인다.
  • 40. Data File ID, Action, SourceXml, ExpectedHtml Extref,crossref,<extref id='abc'/>,<a href='abc.html'>abc</a> TTerm,crossref,<testterm id='abc'/>,<a href='abc.html'>abc</a> TTerms,crossref,<testterms id='abc'/>,<a href='abc.html'>abcs</a> def executeDataDrivenTest filename dataFile = File.open(filename) dataFile.each_line do | line | desc, action, part2 = line.split(",") sourceXml, expectedHtml, leftOver = part2.split(",") if "crossref"==action.strip generateAndVerifyHtml sourceXml, expectedHtml, desc else # 새 '동사'들은 위에 elseif 형태로 추가할 수 있다. report_error("unknown action" + action.strip) end end end
  • 41. 10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
  • 42. 테스트 내에 조건문이 있으면 같은 테스트가 상황에 따라 다르게 실행될 수 있다는 점에서 나쁘다. 신뢰가 떨어진다.
  • 43. 조건문을 넣는 이유 테스트 도중 이미 잘못된 부분을 찾았다면 나머지 단언문은 실행해봐야 별 도움이 안 되니까 아예 실행하고 싶지 않다. 코드가 읽기 어려워진다. 기대 결과 값과 비교하는 실제 결과에 대해 다양한 상황을 허용해야 한다. 코드가 읽기 어려워진다. 하나의 테스트 메소드를 여러 상황에서 재사용하고 싶다. 절대 하지마
  • 44. if문 제거하기 보호 단언문을 쓴다.테스트 내 조건문 로직이 없어도 테스트 에러를 낼 수 있는 곳에 단언문이 걸리게 할 수 있다.
  • 45. List lineItems = invoice.getLineItems(); if (lineItems.size() == 1) { LineItem expected = new LineItem(invoice, product, 5, new BigDecimal("30"), new BigDecimal("69.96")); LineItem actItem = (LineItem) lineItems.get(0); assertEquals("invoice", expected, actItem); } else { fail("invoice should have exactly one line item"); }
  • 46. List lineItems = invoice.getLineItems(); assertEquals("number of items", lineItems.size(), 1); LineItem expected = new LineItem(invoice, product, 5, new BigDecimal("30"), new BigDecimal("69.96")); LineItem actItem = (LineItem) lineItems.get(0); assertEquals("invoice", expected, actItem);
  • 47. 반복문 제거하기 테스트 메소드에 반복문이 들어가면 다음과 같은 문제가 생긴다. 테스트할 수 없는 테스트 코드가 추가되는 셈이 된다. 애매한 테스트가 되기 쉽다. 복잡하다. 테스트를 안쓰게 된다. 해결법 테스트 유틸리티 메소드에 로직을 옮겨놓고 의도가 잘 드러나게 이름을 정하면 된다.
  • 48. 10장에서 이야기 하는 것 테스트 결과 검증 방법 상태 검증 동작 검증 테스트 코드 작성 노하우 테스트 코드 중복 줄이기 테스트 내 조건문 로직 피하기 이해하기 쉬운 테스트를 작성하기
  • 49. 이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
  • 50. 이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
  • 51. 함수의 가장 마지막 줄을 먼저 작성해본다. 테스트를 먼저 작성해 본다. 단언문들을 먼저 작성한다. 변수를 먼저 사용하고, 나중에 선언한다.
  • 52. 이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
  • 53. 일정한 추상수준을 유지하는 것을 의미 테스트 유틸리티 메소드를 호출하는 방식으로 코딩을 함으로써 테스트 메소드를 작성하는 동안에는 SUT의 요구 사항에만 집중하게 한다. 어떤 객체나 결과가 필요한지만 작성해둔다. 정의하지 않은 채로 먼저 사용하는 유틸리티 메소드는 테스트 자동 로직이 들어갈 장소 역할을 하게 된다. 테스트 유틸리티 메소드를 나중에 구현한다.
  • 54. 이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
  • 55. 테스트 유틸리티 메소드를 구현할 시점 테스트 유틸리티 메소드를 사용하는 테스트 메소드 작성이 끝났을때 테스트 유틸리티 메소드를 작성할때 테스트 유틸리티용 테스트를 작성한다.
  • 56. 이해하기 쉬운 테스트 작성 요령 거꾸로 작업 밖에서 안으로 작업 테스트 주도 개발로 테스트 유틸리티 메소드 작성 재사용 가능한 검증 로직을 둘 위치
  • 57. 재사용 가능한 테스트 로직은 어디에 둬야 할까? 테스트 케이스 클래스 안 테스트케이스 상위클래스 테스트 도우미 안
  • 58.