SlideShare une entreprise Scribd logo
1  sur  91
Télécharger pour lire hors ligne
박성철	
data	service	개발	그룹
UI
V
SW
자바 테스트 자동화
->
Feedback
->
Feedback
기능 테스트 / UI 테스트 (Record & Playback)

통합 테스트

단위 테스트
with CI & Build Tool
개발자 테스트 / 프로그래머 테스트

소스 코드의 가장 작은 단위를 테스트

테스트 코드에 의해 수시로 수행

개발 속도와 품질을 동시에 향상
JUnit
JUnit
프로그래머 중심의 자바용 테스트 프레임워크. 단위 테스트
를 위한 xUnit 아키텍처의 한 종류
xUnit : http://en.wikipedia.org/wiki/XUnit
JUnit : http://junit.org
JUnit 설계 목표
유용한 테스트를 작성하는데 도움이 되어야 함
시간이 지나도 가치 있는 테스트를 작성하는데 도움이 되어야 함
코드를 재사용함으로써 테스트 작성 비용을 낮추는데 도움이 되
어야 함
JUnit
JUnit is an open source framework which is used for writing & running tests.
Provides Assertions for testing expected results.
Provides Test runners for running tests.
JUnit tests allow you to write code faster which increasing quality
JUnit is elegantly simple. It is less complex & takes less time.
JUnit tests can be run automatically and they check their own results and
provide immediate feedback.
JUnit tests can be organized into test suites containing test cases and even
other test suites.
Junit shows test progress in a bar that is green if test is going fine and it
turns red when a test fails.
JUnit 4
@Test
@Before, @After
@BeforeClass, @AfterClass
@Ignore(“any message”)
@RunWith
@Parameters, @Parameter
@SuiteClasses
단위 테스트를 정의한 메서드
조건
@Test로 표시
반환 없음(void)
공개 메서드
@Test(expected=SomeException.class)
@Test(timeout=nnn)
JUnit
fail
assertTrue
assertFalse
assertEquals
assertArrayEquals
assertNull
assertNotNull
assertSame
assertNotSame
assertThat
import static org.junit.Assert.*;
JUnit
assumeNoException(Throwable t)
assumeNotNull(Object… o)
assumeTrue(boolean b)
assumeThat(T actual, Matcher<T> matcher)
import static org.junit.Assume.*;


(test fixture)
테스트의 기반이 되는 일관된 실행 환경
테스트 수행 전에 테스트 설비를 설치(setup) 작업
과 테스트 수행 후에 초기 상태로 설비를 해체
(tearDown)하는 작업 필요
@Before, @After
@BeforeClass, @AfterClass (정적 메서드)
자바 테스트 자동화
자바 테스트 자동화


(hamcrest)
복잡한 단언문을 서술적으로 가독성 높게 작성 가능
실패 시 문제 파악에 도움이 되는 정보 제공
http://hamcrest.org/
JUnit 4 , assertThat(T actual, Matcher<T> matcher)
핵심 매처: org.hamcrest.CoreMatchers

전체 매처: org.hamcrest.Matchers
assertTrue(result.contains(“x”) || result.contains(“y”) || result.contains(“z”));



assertThat(result, is(hasItem(anyOf(equalTo(“x”, equalTo(“y”), equalTo(“z”)))));
import static org.hamcrest.CoreMatchers.*;
논리
allOf(), anyOf():
not(): 비교 결과 부정 또는 다름
컬렉션(Collection)
hasItem(), hasItems():
문자열
contansString(), containsStringIgnoringCase():
startWith(), startsWithIgnoringCase():
endsWith(), endsWithIgnoringCase():
기본
equalTo(): 두 객체가 동일한지 판단
is(Matcher matcher): 단언문의 서술성을 높임, 기능 없음
is(Object o): equalTo()와 동일
anything(): 항상 참
객체
any(), instanceOf(): 특정 유형의 클래스면 참
isA(): is(instanceOf(…))
notNullValue(), nullValue(): 널 확인
sameInstance(): 동일 객체 인스턴스 확인
AssertJ
import static org.assertj.core.api.Assertions.*;
API
(fluent) API
assertThat(fellowshipOfTheRing)
.filteredOn(character -> character.getName().contains("o") )
.containsOnly(aragorn, frodo, legolas, boromir);
assertThat(frodo.getName()).isEqualTo("Frodo");
assertThat(frodo).isNotEqualTo(sauron).isIn(fellowshipOfTheRing);
assertThat(fellowshipOfTheRing).extracting(“name")
.contains("Boromir", "Gandalf", "Frodo", "Legolas")
.doesNotContain("Sauron", "Elrond");
(Test Double)
No man is an island entire of itself;
every man is a piece of the
continent, a part of the main;
object
object
SUT

(small & light)


(huge&
heavy)
SUT

(small & light)


(huge&
heavy)
제라드 메스자로스(Gerad Meszaros)가 xUnit
Test Patterns 책을 통해 소개한 용어
영화에서 위험한 장면에서 배우 대신 등장하는 스
턴트 대역(Stunt Double)을 차용
특정 객체를 사용해서 테스트를 진행하기 어려울
경우, 그 객체 대신 사용하는 테스트용 객체
훨씬 협조적이고 원하는 대로 테스트를 작성할 수
있게 해주는 대역 객체
테스트 대상을 의존 객체와 관계를 끊고 격리시킬 때
느린 테스트를 더 빠르게 만들어 자주 실행하고 싶을 때
예측 불가능한 요소를 통제하여 테스트하고 싶을 때
특수한 상황을 시뮬레이션하고 싶을 때
감춰진 정보를 얻어내는 용도로 활용하고 싶을 때
통합 환경 부재로 실제와 같은 대용품 객체를 만들고 싶을 때
필요한 객체를 점진적으로 설계하는 방식(Need-Driven
Development)으로 테스트 및 구현을 확장해 나가고 싶을 때
자바 테스트 자동화


(Dummy Object)
단순한 빈 껍데기 객체가 필요할 때 사용
테스트 대상 객체의 생성자나 메서드의 인자로 전
달하는 용도
아무런 기능도 구현되지 않으며 호출됐을 때 정상
동작은 보장되지 않음
일부에선 호출을 가정해서 만들었다고 보기 힘들기
때문에 만일 호출시엔 예외를 발생시켜야 한다고
말함 (http://toby.epril.com/?p=706)
(Test Stub)
필요한 만큼 최소한의 기능만 구현
주로 정해진 값을 반환하도록 하드 코딩
public class LoggerStub implements Logger {
public void log(LogLevel level, String message) {
throw new UnsupportedOperationException();
}
public LogLevel getLogLevel() {
return LogLevel.WARN;
}
}
(Test Spy)
사용 여부, 호출 내용, 처리 결과 등을 기록 했다가 나
중에 확인 가능
public class LogTargetSpy implements LogTarget {
public void write(Level level, String message) {
log.add(level + “:” + message);
}
boolean received(Level level, String message) {
return log.contains(level + “:” + message);
}
}
(Fake Object)
원 객체보다는 단순하지만 여러 테스트에서 공용으로 사용할 수
준으로 구현된 객체
테스트 토막을 테스트 시나리오 별로 따로 만드는 번거로움을 해
결
실제 객체의 대용품(ex 실 DB 대신 메모리에 저장하는 DAO)
(Mock Object)
특정 조건에 정해진 행위를 취함
상태보다는 행위 기반으로 테스트를 작성
모의 객체 제작용 프레임워크를 주로 활용해서 제작
모의객체는 스텁이 아니다(Mocks Aren't Stubs)

http://testing.jabberstory.net/
Mockito
자바 테스트 자동화
import static org.mockito.Mockito.*;


AbcService serviceMock = mock(AbcService.class)
Mockito
target class
mocked target
mock()
Test
생성 반환
thenReturn(T value)
thenThrow(Throwable t)

thenThrow(Class<? extends Throwable> t)
then(Answer answer)

thenAnswer(Answer answer)
thenCallRealMethod()
when() thenReturn()
when(someMock.getSomething()).thenReturn(TEST_NUMBER_OF_LEAFS);
doThrow(Throwable toBeThrown)
doThrow(Class<? extends Throwable> toBeThrown)
doAnswer(Answer answer)
doCallRealMethod()
doNothing()
Mockito doXxx()
doThrow(SomeException.class).when(someMock).getSomething();
doThrow(new RuntimeException()).when(mockedList).clear();
mockedList.clear(); //throws RuntimeException
when(mock.someMethod(anyString())).thenAnswer(
(InvocationOnMock invocation) -> {
Object[] args = invocation.getArguments();
return "called with arguments: " + args;
}
});
System.out.println(mock.someMethod("foo"));
ArrayList clear


(Argument Matcher)
when(mockedList.get(anyInt())).thenReturn(“element”);
System.out.println(mockedList.get(999)) // print “element”
verify(mockedList).get(anyInt());
when(mockedList.contains(argThat(isValid())).thenReturn(“element”);
Mockito
Hamcrest (argThat() )
1/3
any() Matches anything, including nulls
any(Class<T> clazz) Matches any object, including nulls
anyBoolean() Any boolean or non-null Boolean
anyByte() Any byte or non-null Byte.
anyChar() Any char or non-null Character.
anyCollection() Any non-null Collection.
anyCollectionOf(Class<T> clazz) Generic friendly alias to anyCollection().
anyDouble() Any double or non-null Double.
anyFloat() Any float or non-null Float.
anyInt() Any int or non-null Integer.
anyList() Any non-null List.
anyListOf(Class<T> clazz) Generic friendly alias to anyList().
anyLong() Any long or non-null Long.
anyMap() Any non-null Map.
anyMapOf(Class<K> keyClazz, Class<V> valueClazz) Generic friendly alias to
anyMap().
anyObject() Matches anything, including null.
anySet() Any non-null Set.
anySetOf(Class<T> clazz) Generic friendly alias to anySet().
anyShort() Any short or non-null
anyString() Any non-null String
anyVararg() Any vararg, meaning any number and values of arguments.
2/3
Hamcrest
argThat(org.hamcrest.Matcher<T> matcher)
booleanThat(org.hamcrest.Matcher<Boolean> matcher)
byteThat(org.hamcrest.Matcher<Byte> matcher)
charThat(org.hamcrest.Matcher<Char> matcher)
doubleThat(org.hamcrest.Matcher<Double> matcher)
floatThat(org.hamcrest.Matcher<Float> matcher)
intThat(org.hamcrest.Matcher<Integer> matcher)
longThat(org.hamcrest.Matcher<Long> matcher)
shortThat(org.hamcrest.Matcher<Short> matcher)
contains(String substring) String argument that contains the given
substring.
matchers.
endsWith(String suffix) String argument that ends with the given suffix.
matches(String regex) String argument that matches the given regular
expression.
refEq(T value, String... excludeFields) Object argument that is reflection-
equal to the given value with support for excluding selected fields from a
class.
startsWith(String prefix) String argument that starts with the given
prefix.
3/3
eq(boolean value) boolean argument that is equal to the given value.
eq(byte value) byte argument that is equal to the given value.
eq(char value) char argument that is equal to the given value.
eq(double value) double argument that is equal to the given value.
eq(float value) float argument that is equal to the given value.
eq(int value) int argument that is equal to the given value.
eq(long value) long argument that is equal to the given value.
eq(short value) short argument that is equal to the given value.
eq(T value) Object argument that is equal to the given value.
isA(Class<T> clazz) Object argument that implements the given class.
isNotNull() Not null argument.
isNotNull(Class<T> clazz) Not null argument, not necessary of the given
class.
isNull() null argument.
isNull(Class<T> clazz) null argument.
notNull() Not null argument.
notNull(Class<T> clazz) Not null argument, not necessary of the given
class.
same(T value) Object argument that is the same as the given value.
import static org.mockito.AdditionalMatchers.*;
and(first, second), or(first, second), not(first)
aryEq(), cmpEq(Comparable<T> value)
eq(value, delta), geq(value), gt(value), leq(value), lt(value)
find(String regex)
verify(T mock)
verify(T mock, VerificationMode mode)
times(int num) num회 호출
never() 호출되지 않음
atLeastOnce() 최소한 한 번 이상 호출
atLeast(int min) min회 이상 호출
atMost(int max) max회 이하 호출
only() 마지막 호출
timeout(int millis) 지정한 시간 안에 처리 종료
verify(mockedList).add(“once");
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("five times");
verify(mockedList, atMost(5)).add("three times");
public static InOrder inOrder(Object... mocks)
//given
List singleMock = mock(List.class);
// when
singleMock.add("was added first");
singleMock.add("was added second");
// than
InOrder inOrder = inOrder(singleMock);
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");
@Test
public void shouldStubMethodAndCallRealNotStubbedMethod(){
//given
Flower realFlower = new Flower();
realFlower.setNumberOfLeafs(ORIGINAL_NUMBER_OF_LEAFS);
Flower flowerSpy = spy(realFlower);
willDoNothing().given(flowerSpy).setNumberOfLeafs(anyInt());
//when
flowerSpy.setNumberOfLeafs(NEW_NUMBER_OF_LEAFS);
/than
verify(flowerSpy).setNumberOfLeafs(NEW_NUMBER_OF_LEAFS);
assertEquals(flowerSpy.getNumberOfLeafs(),
ORIGINAL_NUMBER_OF_LEAFS);
}
,
JUnit
JUnit 4
@Test
@Before, @After
@BeforeClass, @AfterClass
@Ignore(“any message”)
@RunWith
@Parameters
@SuiteClasses
작성된 JUnit 테스트를 실행
org.junit.runner.Runner 구현
@RunWith
JUnit에서 기본으로 여러가지 실
행기 제공
기본은 org.junit.runners.JUnit4
클래스
Runner
ParentRunner
Suite
BlockJUnit4-
ClassRunner
JUnit4
Theories
Categories
Enclosed
Parameterized
한 클래스에 여러 테스트 클래스가 포함되어 있을 때 사용
org.junit.runner.Enclosed 

@RunWith(Enclosed.class)
@RunWith(Enclosed.class)
public class SomeTest {
public class SomeInnerTest {
@Test public void test() {…}
}
public class AnotherInnerTest {
@Test public void test() {…}
}
}


(Test Suite)
여러 테스트를 한 묶음으로 모아서 실행하려고 할 때 사용
org.junit.runner.Suite 실행기로 실행
@RunWith(Suite.class)
@Suite.SuiteClasses로 한 묶음으로 묶을 테스트
클래스 또는 테스트 모음 클래스 지정
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestFeatureLogin.class, TestFeatureLogout.class,
TestFeatureNavigate.class, TestFeatureUpdate.class })
public class FeatureTestSuite { }
한 테스트 모음을 여러 분류로 구분해서 독립적으로 실행
@Category로 테스트 클래스나 테스트 메서드를 특정 분류로 지정 (ex
@Category(UnitTest.class))
@IncludeCategory와 @ExcludeCategory로 테스트에 포함시킬 테스트
지정
org.junit.runner.Categories 

@RunWith(Categories.class)
@RunWith(Categories.class)
@IncludeCategory(CommunityVersion.class)
@ExcludeCategory(EnterpriseVersion.class)
@SuiteClasses( { A.class, B.class })
public class FeatureTestSuite {
}
테스터가 입력값과 기대값을 표 형태로 제공하고 테스트를
수행
경계 값 등 여러 값의 조합으로 다양한 시나리오를 제공 가능
Junit에서는 매개변수화 테스트와 이론으로 지원
user id location time benefit
park 명동 9:00 12
kim 강남 12:00 4
lee 홍대 10:00 9
choi 부산 22:00 0


(Parameterized Test)
테스트 클래스를 생성할 때 여러가지 초기 상태를 지정하고 반복 수행
org.junit.runners.Parameterized 실행기 사용
@Parameters 어노테이션으로 인자 목록 정의
name 속성으로 테스트 이름 부여 가능
{index} : 인자 순번
{#}: 0부터 시작, 인자 값
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class FibonacciTest {
@Parameterized.Parameters(name="{index}: fib({0})={1}")
public static Collection<Object[]> args() {
return Arrays.asList(new Object[][] {
{ 0, 0 }, { 1, 1 }, { 2, 1 }
});
}
……
}
private int input;
private int expected;
public FibonacciTest(int input, int expected) {
this.input = input;
this.expected = expected;
}
@Parameterized.Parameter(0)
public int input;
@Parameterized.Parameter(1)
public int expected;


(Theories)
무한대의 데이터에 대한 다양한 조합으로 테스트 수행
org.junit.runners.Theories 실행기 사용
: @DataPoint, @DataPoints
@FromDataPoints
assumeXxx
수행할 테스트에는 @Test 대신 @Theory 표시
@RunWith(Theories.class)
public class AdultValidationTest {
@DataPoints(“uid”) public static long[] UIDS =
new long[] { 10, 33, 452, 4321 };
@DataPoints(“cid”) public static long[] CIDS =
new long[] { 1, 53, 100, 984, 1343 };
@Theory public void validate(@FromDataPoints("uid")long userId,
@FromDataPoints("cid")long contentId){
User user = UserService.findById(userId);
assumeTrue(user.isAdult());
Content content = ContentService.findById(contentId);
assertTrue(content.isValid(user));
}
}


JUnit
public class MemberJUnitWithSpringTest {
AnnotationConfigApplicationContext appctx;
MemberService memberService;
@Before
public void setUp() {
appctx = new AnnotationConfigApplicationContext(Config.class);
memberService = appctx.getBean(MemberService.class);
}
@Test
public void test() throws Exception {
assertEquals(memberService.getMember(1).getName(), " ");
assertEquals(memberService.getMember(2).getName(), " ");
assertEquals(memberService.getMember(3).getName(), " ");
}
@After
public void teardown() {
appctx.close();
}
}
애플리케이션 컨텍스트 관리와 캐시
테스트 설비 의존관계 주입
트랜잭셕 관리
통합 테스트에 유용한 스프링의 클래스 라이브러리 제공
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
public class MemberJUnitWithManualSpringTest {
@Autowired
public MemberService memberService;
@Test
public void test() throws Exception {
assertEquals(memberService.getMember(1).getName(), " ");
assertEquals(memberService.getMember(2).getName(), " ");
assertEquals(memberService.getMember(3).getName(), " ");
}
}
SpringJUnit4ClassRunner
@DirtiesContext
public void test() throws Exception { …… }
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class ContextDirtyingTests {
@DirtiesContext
public class ContextDirtyingTests {
초기화가 오래 걸리는 애플리케이션 컨텍스트 재사용
@DirtiesContext:
,
@Transactional을 테스트 클래스에 지정할 경우 매 테스트마다 자동으로 원복
(rollback) 처리가 됨
@TransactionConfiguration으로 빈 설정과 별도로 테스트 클래스 수준의 트
랜잭션 설정 추가 가능
@TransactionConfiguration(transactionManager = “txMgr",
defaultRollback = false)
@Transactional
public class CustomConfiguredTransactionalTests {
@Rollback로 클래스 수준의 기본 트랜잭션 설정을 메서드 단위에서 변경 가능
@Rollback(false)
public void testProcessWithoutRollback() { …… }
(commit)
트랜잭션 전후에 로직 실행 가능
@BeforeTransaction
public void beforeTransaction() {
……
}
@AfterTransaction
public void afterTransaction() {
……
}
public class PartiallyTransactionalTests {
@Transactional
public void testProcessWithTransaction(){ …… }
public void testProcessWithoutTransaction(){ …… }
@WebAppConfiguration을 지정한 테스트 클래스의 애플리케이션 컨텍스트는
WebApplicationContext가 됨
기본으로 “file:src/main/webapp"을 웹 루트 경로로 사용
웹 루트 경로를 @WebAppConfiguration의 인자로 지정 가능
MockHttpServletRequest나 MockHttpSession을 주입 받고 리퀘스트와 세
션 스코프 빈을 테스트 할 수 있음
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public void ScopedBeanTests() {
@Autowired WebApplicationContext wac;
@Autowired MockHttpServletRequest request;
……
}
WebApplicationContext
HttpServletRequest
MVC
MVC
DB
+
WACMVC
UI
Client
HttpServletRequest
HttpServletResponse
WAS
Test
Mock Request
Mock Response
MockMVC
Spring MVC
Spring MVC
MVC
MVC
스프링 MVC 테스트 프레임워크
유창한(fluent) API로 서술적으로 테스트 조건과 단정문을 작성
서블릿 컨테이너 없이 스프링 MVC의 모든 동작과 뷰(View) 처
리 결과까지 테스트
MockMvcBuilders를 사용해서 생성
mockMvc = standaloneSetup(new AccountController())
.defaultRequest(get("/")
.contextPath("/app").servletPath("/main")
.accept(MediaType.APPLICATION_JSON).build();
mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
Web Application Context
MVC
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=AppConfig.class)
@WebAppConfiguration
public class ControllerTest {
@Autowired
WebApplicationContext wac;
MockMvc mockMvc;
@Before public void init() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.alwaysDo(MyResultLogger.log())
.alwaysExpect(status().isOk())
.build();
}
…
}
MVC
mockMvc.perform(
get("/test/")
.header(“x-requested-with", "XMLHttpRequest")
.accept(MediaType.APPLICATION_JSON))
.andExpect(handler().handlerType(MyController.class))
.andExpect(handler().methodName("test"))
.andExpect(status().isOk());
}
202
ResultActions perform(RequestBuilder requestBuilder)
get “/test/“ URL ajax JSON


(MockMvcRequestBuilders)
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
…
mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
mockMvc.perform(fileUpload(“/doc").file(“a1", "ABC".getBytes("UTF-8")));
mockMvc.perform(get("/hotels").param("foo", "bar"));
delete(), fileUpload(), get(), post(), put() 다섯
가지 HTTP 메소드별 빌더 생성 정적 메서드 제공
공통적으로 url 템플릿 기능 제공
fileUpload()는
MockMultipartHttpServletRequestBuilder 반환,
나머지는 MockHttpServletRequestBuilder 반환


(MockMvcRequestBuilders)
accept(MediaType... mediaTypes)
buildRequest(javax.servlet.ServletContext servletContext)
characterEncoding(java.lang.String encoding)
content(byte[] content)
content(java.lang.String content)
contentType(MediaType mediaType)
contextPath(java.lang.String contextPath)
cookie(javax.servlet.http.Cookie... cookies)
createServletRequest(javax.servlet.ServletContext servletContext)
flashAttr(java.lang.String name, java.lang.Object value)
flashAttrs(java.util.Map<java.lang.String,java.lang.Object> flashAttributes)
header(java.lang.String name, java.lang.Object... values)
headers(HttpHeaders httpHeaders)
isMergeEnabled()
locale(java.util.Locale locale)
merge(java.lang.Object parent)
param(java.lang.String name, java.lang.String... values)
pathInfo(java.lang.String pathInfo)
principal(java.security.Principal principal)
requestAttr(java.lang.String name, java.lang.Object value)
secure(boolean secure)
servletPath(java.lang.String servletPath)
session(MockHttpSession session)
sessionAttr(java.lang.String name, java.lang.Object value)
sessionAttrs(java.util.Map<java.lang.String,java.lang.Object> sessionAttributes)
with(RequestPostProcessor postProcessor)
ContentResultMatchers content()
CookieResultMatchers cookie()
FlashAttributeResultMatchers flash()
ResultMatcher forwardedUrl(java.lang.String expectedUrl)
HandlerResultMatchers handler()
HeaderResultMatchers header()
<T> ResultMatcher jsonPath(java.lang.String expression, org.hamcrest.Matcher<T>
matcher)
JsonPathResultMatchers jsonPath(java.lang.String expression, java.lang.Object...
args)
ModelResultMatchers model()
ResultMatcher redirectedUrl(java.lang.String expectedUrl)
RequestResultMatchers request()
StatusResultMatchers status()
ViewResultMatchers view()
XpathResultMatchers xpath(java.lang.String expression,
java.util.Map<java.lang.String,java.lang.String> namespaces, java.lang.Object...
args)
XpathResultMatchers xpath(java.lang.String expression, java.lang.Object... args)
• Request attribute test ( Attribute )
• .andExpect(request().attribute(.., ..))
• Session attribute test ( )
• .andExpect(request().sessionAttribute(.., ..))
• Async test ( Servlet 3.0, Spring 3.2
)
• .andExpect(request(). asyncStarted(.., ..))
• ?
• .andExpect(request(). asyncNotStarted(.., ..))
• ?
• .andExpect(request(). asyncResult(.., ..))
• ?
• Handler type test ( Handler
)
• .andExpect(handler().handlerType(..))
• Handler method name test ( Handler
)
• .andExpect(handler().methodName(..))
• Handler method type test ( Handler
)
• .andExpect(handler().method(..))
• Model attrbute test ( Model )
• .andExpect(model().attribute(..))
• .andExpect(model().attributeExists(..))
• .andExpect(model().attributeErrorCount(..))
• .andExpect(model().attributeHasErrors(..))
• .andExpect(model().attributeHasNoErrors(..))
• .andExpect(model().attributeHasFieldErrors(..))
• .andExpect(model().errorCount(..))
• .andExpect(model().hasErrors(..))
• .andExpect(model().hasNoErrors(..))
• Status test ( )
• .andExpect(status().is(..))
• ( 200: … )
• org.springframework.http HttpStatus
• Error message test ( )
• .andExpect(status().reason(..))
• .
• Header test ( )
• .andExpect(header().string(..))
• .andExpect(header().longValue(..))
• ContentType test( contentType )
• .andExpect(content().contentType(..))
• .andExpect(content().contentTypeCompatibleWith(..))
• Encoding test ( content )
• .andExpect(content().encoding(..))
• Content test ( content )
• .andExpect(content().string(..)) : content
• .andExpect(content().bytes(..)) : content byte
• .andExpect(content().xml(..)) : content xml dom
• .andExpect(content().node(..)) : content xml dom node
• .andExpect(content().source(..)) : content xml dom source
• View name test ( View name )
• .andExpect(view().name(..))
• Forwarded url test( URL )
• .andExpect(forwardedUrl(..))
• Redirected url test ( URL )
• .andExpect(redirectedUrl(..))
• Flash attribute test ( Spring 3.1 Flash
attribute )
• .andExpect(flash().attribute(..)) : attribute
• .andExpect(flash(). attributeExists(..)) : attribute
• .andExpect(flash(). attributeCount(..)) : attribute
자바 테스트 자동화
• ? (Right-BICEP, )
- Right - ?
- Boundary - correct ?
- Inverse - ?
- Cross-check - ?
- Error condition - ?
- Performance - ?
• (A-trip)
- Automatic (IDE, CI)
- Thorough (Coverage )
- Repeatable
- Independent (Fixture setting)
- Professional ( )
Inside-out vs Outside-in
vs
.
.


.
Outside-in .
: -> ->
: =
(spec.)
(Testability)
: Simple Design
“사전에 테스트를 고려하여 개발한게 아니다보니 억지로 테스트를 만들게 된다. 그
리고 언젠가 부터 테스트는 mocking으로 도배되거나 @Ignore가 추가되고 있다.”
TDD
/ /
(
)
ATDD
Step 1:
Step 2:
Step 3:
Step 4:
ATDD
Concordion: http://www.concordion.org/
Cucumber: http://cukes.info/
Fitnesse: http://fitnesse.org/
Selenium: http://docs.seleniumhq.org/
and JUnit… ;^)
100%

Contenu connexe

Tendances

[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자NAVER D2
 
Hibernate presentation
Hibernate presentationHibernate presentation
Hibernate presentationManav Prasad
 
[수정본] 우아한 객체지향
[수정본] 우아한 객체지향[수정본] 우아한 객체지향
[수정본] 우아한 객체지향Young-Ho Cho
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄현 수
 
softCours design pattern m youssfi partie 9 creation des objets abstract fact...
softCours design pattern m youssfi partie 9 creation des objets abstract fact...softCours design pattern m youssfi partie 9 creation des objets abstract fact...
softCours design pattern m youssfi partie 9 creation des objets abstract fact...ENSET, Université Hassan II Casablanca
 
An introduction to bootstrap
An introduction to bootstrapAn introduction to bootstrap
An introduction to bootstrapMind IT Systems
 
Domain-Driven-Design 정복기 2탄
Domain-Driven-Design 정복기 2탄Domain-Driven-Design 정복기 2탄
Domain-Driven-Design 정복기 2탄Suhyeon Jo
 
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기 [122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기 NAVER D2
 
Introduction à spring boot
Introduction à spring bootIntroduction à spring boot
Introduction à spring bootAntoine Rey
 
Hibernate ppt
Hibernate pptHibernate ppt
Hibernate pptAneega
 
Développement d'applications pour la plateforme Java EE
Développement d'applications pour la plateforme Java EEDéveloppement d'applications pour la plateforme Java EE
Développement d'applications pour la plateforme Java EESabri Bouchlema
 
Formation JAVA/J2EE
Formation JAVA/J2EEFormation JAVA/J2EE
Formation JAVA/J2EEInes Ouaz
 
c# programmation orientée objet (Classe & Objet)
c# programmation orientée objet (Classe & Objet)c# programmation orientée objet (Classe & Objet)
c# programmation orientée objet (Classe & Objet)Mahfoud EL HOUDAIGUI
 
Deview 2013 mobile browser internals and trends_20131022
Deview 2013 mobile browser internals and trends_20131022Deview 2013 mobile browser internals and trends_20131022
Deview 2013 mobile browser internals and trends_20131022NAVER D2
 
도메인 주도 설계의 본질
도메인 주도 설계의 본질도메인 주도 설계의 본질
도메인 주도 설계의 본질Young-Ho Cho
 
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델명환 안
 
Mise en oeuvre des Frameworks de Machines et Deep Learning pour les Applicati...
Mise en oeuvre des Frameworks de Machines et Deep Learning pour les Applicati...Mise en oeuvre des Frameworks de Machines et Deep Learning pour les Applicati...
Mise en oeuvre des Frameworks de Machines et Deep Learning pour les Applicati...ENSET, Université Hassan II Casablanca
 

Tendances (20)

[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자
 
Hibernate presentation
Hibernate presentationHibernate presentation
Hibernate presentation
 
[수정본] 우아한 객체지향
[수정본] 우아한 객체지향[수정본] 우아한 객체지향
[수정본] 우아한 객체지향
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄
 
Presentation1.pptx
Presentation1.pptxPresentation1.pptx
Presentation1.pptx
 
softCours design pattern m youssfi partie 9 creation des objets abstract fact...
softCours design pattern m youssfi partie 9 creation des objets abstract fact...softCours design pattern m youssfi partie 9 creation des objets abstract fact...
softCours design pattern m youssfi partie 9 creation des objets abstract fact...
 
An introduction to bootstrap
An introduction to bootstrapAn introduction to bootstrap
An introduction to bootstrap
 
Domain-Driven-Design 정복기 2탄
Domain-Driven-Design 정복기 2탄Domain-Driven-Design 정복기 2탄
Domain-Driven-Design 정복기 2탄
 
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기 [122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
[122]책에서는 맛볼 수 없는 HTML5 Canvas 이야기
 
Introduction à spring boot
Introduction à spring bootIntroduction à spring boot
Introduction à spring boot
 
Cours design pattern m youssfi partie 6 proxy
Cours design pattern m youssfi partie 6 proxyCours design pattern m youssfi partie 6 proxy
Cours design pattern m youssfi partie 6 proxy
 
Hibernate ppt
Hibernate pptHibernate ppt
Hibernate ppt
 
Développement d'applications pour la plateforme Java EE
Développement d'applications pour la plateforme Java EEDéveloppement d'applications pour la plateforme Java EE
Développement d'applications pour la plateforme Java EE
 
Formation JAVA/J2EE
Formation JAVA/J2EEFormation JAVA/J2EE
Formation JAVA/J2EE
 
c# programmation orientée objet (Classe & Objet)
c# programmation orientée objet (Classe & Objet)c# programmation orientée objet (Classe & Objet)
c# programmation orientée objet (Classe & Objet)
 
Support JEE Servlet Jsp MVC M.Youssfi
Support JEE Servlet Jsp MVC M.YoussfiSupport JEE Servlet Jsp MVC M.Youssfi
Support JEE Servlet Jsp MVC M.Youssfi
 
Deview 2013 mobile browser internals and trends_20131022
Deview 2013 mobile browser internals and trends_20131022Deview 2013 mobile browser internals and trends_20131022
Deview 2013 mobile browser internals and trends_20131022
 
도메인 주도 설계의 본질
도메인 주도 설계의 본질도메인 주도 설계의 본질
도메인 주도 설계의 본질
 
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
 
Mise en oeuvre des Frameworks de Machines et Deep Learning pour les Applicati...
Mise en oeuvre des Frameworks de Machines et Deep Learning pour les Applicati...Mise en oeuvre des Frameworks de Machines et Deep Learning pour les Applicati...
Mise en oeuvre des Frameworks de Machines et Deep Learning pour les Applicati...
 

Similaire à 자바 테스트 자동화

테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)Suwon Chae
 
10장 결과 검증
10장 결과 검증10장 결과 검증
10장 결과 검증dagri82
 
[하코사 세미나] 비전공자의 자바스크립트 도전기
[하코사 세미나] 비전공자의 자바스크립트 도전기 [하코사 세미나] 비전공자의 자바스크립트 도전기
[하코사 세미나] 비전공자의 자바스크립트 도전기 인권 김
 
비전공자의 자바스크립트 도전기
비전공자의 자바스크립트 도전기비전공자의 자바스크립트 도전기
비전공자의 자바스크립트 도전기jeong seok yang
 
Python Unittest
Python UnittestPython Unittest
Python Unittest명규 최
 
I phone 2 release
I phone 2 releaseI phone 2 release
I phone 2 releaseJaehyeuk Oh
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기Heo Seungwook
 
Android UI Test (Espresso/Kakao)
Android UI Test (Espresso/Kakao)Android UI Test (Espresso/Kakao)
Android UI Test (Espresso/Kakao)MDLicht
 
Hacosa js study 2주차
Hacosa js study 2주차Hacosa js study 2주차
Hacosa js study 2주차Seong Bong Ji
 
Swift3 subscript inheritance initialization
Swift3 subscript inheritance initializationSwift3 subscript inheritance initialization
Swift3 subscript inheritance initializationEunjoo Im
 
자바프로그래머를 위한 스칼라
자바프로그래머를 위한 스칼라자바프로그래머를 위한 스칼라
자바프로그래머를 위한 스칼라Jong Gook Bae
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)MIN SEOK KOO
 
Java advancd ed10
Java advancd ed10Java advancd ed10
Java advancd ed10hungrok
 
08장 객체와 클래스 (기본)
08장 객체와 클래스 (기본)08장 객체와 클래스 (기본)
08장 객체와 클래스 (기본)유석 남
 
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 TestOkjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 Testbeom kyun choi
 
Scala, Scalability
Scala, ScalabilityScala, Scalability
Scala, ScalabilityDongwook Lee
 

Similaire à 자바 테스트 자동화 (20)

테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)
 
10장 결과 검증
10장 결과 검증10장 결과 검증
10장 결과 검증
 
[하코사 세미나] 비전공자의 자바스크립트 도전기
[하코사 세미나] 비전공자의 자바스크립트 도전기 [하코사 세미나] 비전공자의 자바스크립트 도전기
[하코사 세미나] 비전공자의 자바스크립트 도전기
 
비전공자의 자바스크립트 도전기
비전공자의 자바스크립트 도전기비전공자의 자바스크립트 도전기
비전공자의 자바스크립트 도전기
 
Python Unittest
Python UnittestPython Unittest
Python Unittest
 
Scala
ScalaScala
Scala
 
I phone 2 release
I phone 2 releaseI phone 2 release
I phone 2 release
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 
Android UI Test (Espresso/Kakao)
Android UI Test (Espresso/Kakao)Android UI Test (Espresso/Kakao)
Android UI Test (Espresso/Kakao)
 
Hacosa js study 2주차
Hacosa js study 2주차Hacosa js study 2주차
Hacosa js study 2주차
 
Swift3 subscript inheritance initialization
Swift3 subscript inheritance initializationSwift3 subscript inheritance initialization
Swift3 subscript inheritance initialization
 
자바프로그래머를 위한 스칼라
자바프로그래머를 위한 스칼라자바프로그래머를 위한 스칼라
자바프로그래머를 위한 스칼라
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
 
Java advancd ed10
Java advancd ed10Java advancd ed10
Java advancd ed10
 
Cygnus unit test
Cygnus unit testCygnus unit test
Cygnus unit test
 
08장 객체와 클래스 (기본)
08장 객체와 클래스 (기본)08장 객체와 클래스 (기본)
08장 객체와 클래스 (기본)
 
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 TestOkjsp 13주년 발표자료: 생존 프로그래밍 Test
Okjsp 13주년 발표자료: 생존 프로그래밍 Test
 
Scala, Scalability
Scala, ScalabilityScala, Scalability
Scala, Scalability
 
Scalability
ScalabilityScalability
Scalability
 
Swt J Face 2/3
Swt J Face 2/3Swt J Face 2/3
Swt J Face 2/3
 

Plus de Sungchul Park

애자일 안한 이야기
애자일 안한 이야기애자일 안한 이야기
애자일 안한 이야기Sungchul Park
 
Java null survival guide
Java null survival guideJava null survival guide
Java null survival guideSungchul Park
 
자바에서 null을 안전하게 다루는 방법
자바에서 null을 안전하게 다루는 방법자바에서 null을 안전하게 다루는 방법
자바에서 null을 안전하게 다루는 방법Sungchul Park
 
변경에 강한 애플리케이션, 유기적 애플리케이션
변경에 강한 애플리케이션, 유기적 애플리케이션변경에 강한 애플리케이션, 유기적 애플리케이션
변경에 강한 애플리케이션, 유기적 애플리케이션Sungchul Park
 
스프링보다 중요한 스프링 이야기
스프링보다 중요한 스프링 이야기스프링보다 중요한 스프링 이야기
스프링보다 중요한 스프링 이야기Sungchul Park
 
Beyond Java: 자바 8을 중심으로 본 자바의 혁신
Beyond Java: 자바 8을 중심으로 본 자바의 혁신Beyond Java: 자바 8을 중심으로 본 자바의 혁신
Beyond Java: 자바 8을 중심으로 본 자바의 혁신Sungchul Park
 
스프링 코어 강의 3부 - 웹 애플리케이션 아키텍처
스프링 코어 강의 3부 - 웹 애플리케이션 아키텍처 스프링 코어 강의 3부 - 웹 애플리케이션 아키텍처
스프링 코어 강의 3부 - 웹 애플리케이션 아키텍처 Sungchul Park
 
스프링 코어 강의 2부 - Java 구성을 활용한 스프링 코어 사용
스프링 코어 강의 2부 - Java 구성을 활용한 스프링 코어 사용스프링 코어 강의 2부 - Java 구성을 활용한 스프링 코어 사용
스프링 코어 강의 2부 - Java 구성을 활용한 스프링 코어 사용Sungchul Park
 
스프링 코어 강의 1부 - 봄 맞이 준비 운동
스프링 코어 강의 1부 - 봄 맞이 준비 운동스프링 코어 강의 1부 - 봄 맞이 준비 운동
스프링 코어 강의 1부 - 봄 맞이 준비 운동Sungchul Park
 
자바8 나머지 공개
자바8 나머지 공개자바8 나머지 공개
자바8 나머지 공개Sungchul Park
 
자바8 람다 나머지 공개
자바8 람다 나머지 공개자바8 람다 나머지 공개
자바8 람다 나머지 공개Sungchul Park
 
java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰Sungchul Park
 
Open Source가 바꾼 자바
Open Source가 바꾼 자바Open Source가 바꾼 자바
Open Source가 바꾼 자바Sungchul Park
 

Plus de Sungchul Park (19)

애자일 안한 이야기
애자일 안한 이야기애자일 안한 이야기
애자일 안한 이야기
 
Java null survival guide
Java null survival guideJava null survival guide
Java null survival guide
 
자바에서 null을 안전하게 다루는 방법
자바에서 null을 안전하게 다루는 방법자바에서 null을 안전하게 다루는 방법
자바에서 null을 안전하게 다루는 방법
 
Java.next
Java.nextJava.next
Java.next
 
변경에 강한 애플리케이션, 유기적 애플리케이션
변경에 강한 애플리케이션, 유기적 애플리케이션변경에 강한 애플리케이션, 유기적 애플리케이션
변경에 강한 애플리케이션, 유기적 애플리케이션
 
스프링보다 중요한 스프링 이야기
스프링보다 중요한 스프링 이야기스프링보다 중요한 스프링 이야기
스프링보다 중요한 스프링 이야기
 
Geeks at SK Planet
Geeks at SK PlanetGeeks at SK Planet
Geeks at SK Planet
 
Beyond Java: 자바 8을 중심으로 본 자바의 혁신
Beyond Java: 자바 8을 중심으로 본 자바의 혁신Beyond Java: 자바 8을 중심으로 본 자바의 혁신
Beyond Java: 자바 8을 중심으로 본 자바의 혁신
 
Java the good parts
Java the good partsJava the good parts
Java the good parts
 
스프링 코어 강의 3부 - 웹 애플리케이션 아키텍처
스프링 코어 강의 3부 - 웹 애플리케이션 아키텍처 스프링 코어 강의 3부 - 웹 애플리케이션 아키텍처
스프링 코어 강의 3부 - 웹 애플리케이션 아키텍처
 
스프링 코어 강의 2부 - Java 구성을 활용한 스프링 코어 사용
스프링 코어 강의 2부 - Java 구성을 활용한 스프링 코어 사용스프링 코어 강의 2부 - Java 구성을 활용한 스프링 코어 사용
스프링 코어 강의 2부 - Java 구성을 활용한 스프링 코어 사용
 
스프링 코어 강의 1부 - 봄 맞이 준비 운동
스프링 코어 강의 1부 - 봄 맞이 준비 운동스프링 코어 강의 1부 - 봄 맞이 준비 운동
스프링 코어 강의 1부 - 봄 맞이 준비 운동
 
자바8 나머지 공개
자바8 나머지 공개자바8 나머지 공개
자바8 나머지 공개
 
자바8 람다 나머지 공개
자바8 람다 나머지 공개자바8 람다 나머지 공개
자바8 람다 나머지 공개
 
팀장 잔소리
팀장 잔소리팀장 잔소리
팀장 잔소리
 
java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰java 8 람다식 소개와 의미 고찰
java 8 람다식 소개와 의미 고찰
 
Open Source가 바꾼 자바
Open Source가 바꾼 자바Open Source가 바꾼 자바
Open Source가 바꾼 자바
 
Work With Engineer
Work With EngineerWork With Engineer
Work With Engineer
 
DDD 산책
DDD 산책DDD 산책
DDD 산책
 

자바 테스트 자동화

  • 2. UI
  • 7. 기능 테스트 / UI 테스트 (Record & Playback) 통합 테스트 단위 테스트 with CI & Build Tool
  • 8. 개발자 테스트 / 프로그래머 테스트 소스 코드의 가장 작은 단위를 테스트 테스트 코드에 의해 수시로 수행 개발 속도와 품질을 동시에 향상
  • 10. JUnit 프로그래머 중심의 자바용 테스트 프레임워크. 단위 테스트 를 위한 xUnit 아키텍처의 한 종류 xUnit : http://en.wikipedia.org/wiki/XUnit JUnit : http://junit.org JUnit 설계 목표 유용한 테스트를 작성하는데 도움이 되어야 함 시간이 지나도 가치 있는 테스트를 작성하는데 도움이 되어야 함 코드를 재사용함으로써 테스트 작성 비용을 낮추는데 도움이 되 어야 함
  • 11. JUnit JUnit is an open source framework which is used for writing & running tests. Provides Assertions for testing expected results. Provides Test runners for running tests. JUnit tests allow you to write code faster which increasing quality JUnit is elegantly simple. It is less complex & takes less time. JUnit tests can be run automatically and they check their own results and provide immediate feedback. JUnit tests can be organized into test suites containing test cases and even other test suites. Junit shows test progress in a bar that is green if test is going fine and it turns red when a test fails.
  • 12. JUnit 4 @Test @Before, @After @BeforeClass, @AfterClass @Ignore(“any message”) @RunWith @Parameters, @Parameter @SuiteClasses
  • 13. 단위 테스트를 정의한 메서드 조건 @Test로 표시 반환 없음(void) 공개 메서드 @Test(expected=SomeException.class) @Test(timeout=nnn)
  • 15. JUnit assumeNoException(Throwable t) assumeNotNull(Object… o) assumeTrue(boolean b) assumeThat(T actual, Matcher<T> matcher) import static org.junit.Assume.*;
  • 16. 
 (test fixture) 테스트의 기반이 되는 일관된 실행 환경 테스트 수행 전에 테스트 설비를 설치(setup) 작업 과 테스트 수행 후에 초기 상태로 설비를 해체 (tearDown)하는 작업 필요 @Before, @After @BeforeClass, @AfterClass (정적 메서드)
  • 19. 
 (hamcrest) 복잡한 단언문을 서술적으로 가독성 높게 작성 가능 실패 시 문제 파악에 도움이 되는 정보 제공 http://hamcrest.org/ JUnit 4 , assertThat(T actual, Matcher<T> matcher) 핵심 매처: org.hamcrest.CoreMatchers
 전체 매처: org.hamcrest.Matchers assertTrue(result.contains(“x”) || result.contains(“y”) || result.contains(“z”));
 
 assertThat(result, is(hasItem(anyOf(equalTo(“x”, equalTo(“y”), equalTo(“z”)))));
  • 20. import static org.hamcrest.CoreMatchers.*; 논리 allOf(), anyOf(): not(): 비교 결과 부정 또는 다름 컬렉션(Collection) hasItem(), hasItems(): 문자열 contansString(), containsStringIgnoringCase(): startWith(), startsWithIgnoringCase(): endsWith(), endsWithIgnoringCase():
  • 21. 기본 equalTo(): 두 객체가 동일한지 판단 is(Matcher matcher): 단언문의 서술성을 높임, 기능 없음 is(Object o): equalTo()와 동일 anything(): 항상 참 객체 any(), instanceOf(): 특정 유형의 클래스면 참 isA(): is(instanceOf(…)) notNullValue(), nullValue(): 널 확인 sameInstance(): 동일 객체 인스턴스 확인
  • 22. AssertJ import static org.assertj.core.api.Assertions.*; API (fluent) API assertThat(fellowshipOfTheRing) .filteredOn(character -> character.getName().contains("o") ) .containsOnly(aragorn, frodo, legolas, boromir); assertThat(frodo.getName()).isEqualTo("Frodo"); assertThat(frodo).isNotEqualTo(sauron).isIn(fellowshipOfTheRing); assertThat(fellowshipOfTheRing).extracting(“name") .contains("Boromir", "Gandalf", "Frodo", "Legolas") .doesNotContain("Sauron", "Elrond");
  • 24. No man is an island entire of itself; every man is a piece of the continent, a part of the main; object object
  • 27. 제라드 메스자로스(Gerad Meszaros)가 xUnit Test Patterns 책을 통해 소개한 용어 영화에서 위험한 장면에서 배우 대신 등장하는 스 턴트 대역(Stunt Double)을 차용 특정 객체를 사용해서 테스트를 진행하기 어려울 경우, 그 객체 대신 사용하는 테스트용 객체 훨씬 협조적이고 원하는 대로 테스트를 작성할 수 있게 해주는 대역 객체
  • 28. 테스트 대상을 의존 객체와 관계를 끊고 격리시킬 때 느린 테스트를 더 빠르게 만들어 자주 실행하고 싶을 때 예측 불가능한 요소를 통제하여 테스트하고 싶을 때 특수한 상황을 시뮬레이션하고 싶을 때 감춰진 정보를 얻어내는 용도로 활용하고 싶을 때 통합 환경 부재로 실제와 같은 대용품 객체를 만들고 싶을 때 필요한 객체를 점진적으로 설계하는 방식(Need-Driven Development)으로 테스트 및 구현을 확장해 나가고 싶을 때
  • 30. 
 (Dummy Object) 단순한 빈 껍데기 객체가 필요할 때 사용 테스트 대상 객체의 생성자나 메서드의 인자로 전 달하는 용도 아무런 기능도 구현되지 않으며 호출됐을 때 정상 동작은 보장되지 않음 일부에선 호출을 가정해서 만들었다고 보기 힘들기 때문에 만일 호출시엔 예외를 발생시켜야 한다고 말함 (http://toby.epril.com/?p=706)
  • 31. (Test Stub) 필요한 만큼 최소한의 기능만 구현 주로 정해진 값을 반환하도록 하드 코딩 public class LoggerStub implements Logger { public void log(LogLevel level, String message) { throw new UnsupportedOperationException(); } public LogLevel getLogLevel() { return LogLevel.WARN; } }
  • 32. (Test Spy) 사용 여부, 호출 내용, 처리 결과 등을 기록 했다가 나 중에 확인 가능 public class LogTargetSpy implements LogTarget { public void write(Level level, String message) { log.add(level + “:” + message); } boolean received(Level level, String message) { return log.contains(level + “:” + message); } }
  • 33. (Fake Object) 원 객체보다는 단순하지만 여러 테스트에서 공용으로 사용할 수 준으로 구현된 객체 테스트 토막을 테스트 시나리오 별로 따로 만드는 번거로움을 해 결 실제 객체의 대용품(ex 실 DB 대신 메모리에 저장하는 DAO)
  • 34. (Mock Object) 특정 조건에 정해진 행위를 취함 상태보다는 행위 기반으로 테스트를 작성 모의 객체 제작용 프레임워크를 주로 활용해서 제작 모의객체는 스텁이 아니다(Mocks Aren't Stubs)
 http://testing.jabberstory.net/
  • 37. import static org.mockito.Mockito.*; 
 AbcService serviceMock = mock(AbcService.class) Mockito target class mocked target mock() Test 생성 반환
  • 38. thenReturn(T value) thenThrow(Throwable t)
 thenThrow(Class<? extends Throwable> t) then(Answer answer)
 thenAnswer(Answer answer) thenCallRealMethod() when() thenReturn() when(someMock.getSomething()).thenReturn(TEST_NUMBER_OF_LEAFS);
  • 39. doThrow(Throwable toBeThrown) doThrow(Class<? extends Throwable> toBeThrown) doAnswer(Answer answer) doCallRealMethod() doNothing() Mockito doXxx() doThrow(SomeException.class).when(someMock).getSomething();
  • 40. doThrow(new RuntimeException()).when(mockedList).clear(); mockedList.clear(); //throws RuntimeException when(mock.someMethod(anyString())).thenAnswer( (InvocationOnMock invocation) -> { Object[] args = invocation.getArguments(); return "called with arguments: " + args; } }); System.out.println(mock.someMethod("foo")); ArrayList clear
  • 41. 
 (Argument Matcher) when(mockedList.get(anyInt())).thenReturn(“element”); System.out.println(mockedList.get(999)) // print “element” verify(mockedList).get(anyInt()); when(mockedList.contains(argThat(isValid())).thenReturn(“element”); Mockito Hamcrest (argThat() )
  • 42. 1/3 any() Matches anything, including nulls any(Class<T> clazz) Matches any object, including nulls anyBoolean() Any boolean or non-null Boolean anyByte() Any byte or non-null Byte. anyChar() Any char or non-null Character. anyCollection() Any non-null Collection. anyCollectionOf(Class<T> clazz) Generic friendly alias to anyCollection(). anyDouble() Any double or non-null Double. anyFloat() Any float or non-null Float. anyInt() Any int or non-null Integer. anyList() Any non-null List. anyListOf(Class<T> clazz) Generic friendly alias to anyList(). anyLong() Any long or non-null Long. anyMap() Any non-null Map. anyMapOf(Class<K> keyClazz, Class<V> valueClazz) Generic friendly alias to anyMap(). anyObject() Matches anything, including null. anySet() Any non-null Set. anySetOf(Class<T> clazz) Generic friendly alias to anySet(). anyShort() Any short or non-null anyString() Any non-null String anyVararg() Any vararg, meaning any number and values of arguments.
  • 43. 2/3 Hamcrest argThat(org.hamcrest.Matcher<T> matcher) booleanThat(org.hamcrest.Matcher<Boolean> matcher) byteThat(org.hamcrest.Matcher<Byte> matcher) charThat(org.hamcrest.Matcher<Char> matcher) doubleThat(org.hamcrest.Matcher<Double> matcher) floatThat(org.hamcrest.Matcher<Float> matcher) intThat(org.hamcrest.Matcher<Integer> matcher) longThat(org.hamcrest.Matcher<Long> matcher) shortThat(org.hamcrest.Matcher<Short> matcher) contains(String substring) String argument that contains the given substring. matchers. endsWith(String suffix) String argument that ends with the given suffix. matches(String regex) String argument that matches the given regular expression. refEq(T value, String... excludeFields) Object argument that is reflection- equal to the given value with support for excluding selected fields from a class. startsWith(String prefix) String argument that starts with the given prefix.
  • 44. 3/3 eq(boolean value) boolean argument that is equal to the given value. eq(byte value) byte argument that is equal to the given value. eq(char value) char argument that is equal to the given value. eq(double value) double argument that is equal to the given value. eq(float value) float argument that is equal to the given value. eq(int value) int argument that is equal to the given value. eq(long value) long argument that is equal to the given value. eq(short value) short argument that is equal to the given value. eq(T value) Object argument that is equal to the given value. isA(Class<T> clazz) Object argument that implements the given class. isNotNull() Not null argument. isNotNull(Class<T> clazz) Not null argument, not necessary of the given class. isNull() null argument. isNull(Class<T> clazz) null argument. notNull() Not null argument. notNull(Class<T> clazz) Not null argument, not necessary of the given class. same(T value) Object argument that is the same as the given value.
  • 45. import static org.mockito.AdditionalMatchers.*; and(first, second), or(first, second), not(first) aryEq(), cmpEq(Comparable<T> value) eq(value, delta), geq(value), gt(value), leq(value), lt(value) find(String regex)
  • 46. verify(T mock) verify(T mock, VerificationMode mode) times(int num) num회 호출 never() 호출되지 않음 atLeastOnce() 최소한 한 번 이상 호출 atLeast(int min) min회 이상 호출 atMost(int max) max회 이하 호출 only() 마지막 호출 timeout(int millis) 지정한 시간 안에 처리 종료 verify(mockedList).add(“once"); verify(mockedList, atLeastOnce()).add("three times"); verify(mockedList, atLeast(2)).add("five times"); verify(mockedList, atMost(5)).add("three times");
  • 47. public static InOrder inOrder(Object... mocks) //given List singleMock = mock(List.class); // when singleMock.add("was added first"); singleMock.add("was added second"); // than InOrder inOrder = inOrder(singleMock); inOrder.verify(singleMock).add("was added first"); inOrder.verify(singleMock).add("was added second");
  • 48. @Test public void shouldStubMethodAndCallRealNotStubbedMethod(){ //given Flower realFlower = new Flower(); realFlower.setNumberOfLeafs(ORIGINAL_NUMBER_OF_LEAFS); Flower flowerSpy = spy(realFlower); willDoNothing().given(flowerSpy).setNumberOfLeafs(anyInt()); //when flowerSpy.setNumberOfLeafs(NEW_NUMBER_OF_LEAFS); /than verify(flowerSpy).setNumberOfLeafs(NEW_NUMBER_OF_LEAFS); assertEquals(flowerSpy.getNumberOfLeafs(), ORIGINAL_NUMBER_OF_LEAFS); } ,
  • 49. JUnit
  • 50. JUnit 4 @Test @Before, @After @BeforeClass, @AfterClass @Ignore(“any message”) @RunWith @Parameters @SuiteClasses
  • 51. 작성된 JUnit 테스트를 실행 org.junit.runner.Runner 구현 @RunWith JUnit에서 기본으로 여러가지 실 행기 제공 기본은 org.junit.runners.JUnit4 클래스 Runner ParentRunner Suite BlockJUnit4- ClassRunner JUnit4 Theories Categories Enclosed Parameterized
  • 52. 한 클래스에 여러 테스트 클래스가 포함되어 있을 때 사용 org.junit.runner.Enclosed 
 @RunWith(Enclosed.class) @RunWith(Enclosed.class) public class SomeTest { public class SomeInnerTest { @Test public void test() {…} } public class AnotherInnerTest { @Test public void test() {…} } }
  • 53. 
 (Test Suite) 여러 테스트를 한 묶음으로 모아서 실행하려고 할 때 사용 org.junit.runner.Suite 실행기로 실행 @RunWith(Suite.class) @Suite.SuiteClasses로 한 묶음으로 묶을 테스트 클래스 또는 테스트 모음 클래스 지정 import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ TestFeatureLogin.class, TestFeatureLogout.class, TestFeatureNavigate.class, TestFeatureUpdate.class }) public class FeatureTestSuite { }
  • 54. 한 테스트 모음을 여러 분류로 구분해서 독립적으로 실행 @Category로 테스트 클래스나 테스트 메서드를 특정 분류로 지정 (ex @Category(UnitTest.class)) @IncludeCategory와 @ExcludeCategory로 테스트에 포함시킬 테스트 지정 org.junit.runner.Categories 
 @RunWith(Categories.class) @RunWith(Categories.class) @IncludeCategory(CommunityVersion.class) @ExcludeCategory(EnterpriseVersion.class) @SuiteClasses( { A.class, B.class }) public class FeatureTestSuite { }
  • 55. 테스터가 입력값과 기대값을 표 형태로 제공하고 테스트를 수행 경계 값 등 여러 값의 조합으로 다양한 시나리오를 제공 가능 Junit에서는 매개변수화 테스트와 이론으로 지원 user id location time benefit park 명동 9:00 12 kim 강남 12:00 4 lee 홍대 10:00 9 choi 부산 22:00 0
  • 56. 
 (Parameterized Test) 테스트 클래스를 생성할 때 여러가지 초기 상태를 지정하고 반복 수행 org.junit.runners.Parameterized 실행기 사용 @Parameters 어노테이션으로 인자 목록 정의 name 속성으로 테스트 이름 부여 가능 {index} : 인자 순번 {#}: 0부터 시작, 인자 값 import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class FibonacciTest { @Parameterized.Parameters(name="{index}: fib({0})={1}") public static Collection<Object[]> args() { return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 } }); } …… }
  • 57. private int input; private int expected; public FibonacciTest(int input, int expected) { this.input = input; this.expected = expected; } @Parameterized.Parameter(0) public int input; @Parameterized.Parameter(1) public int expected;
  • 58. 
 (Theories) 무한대의 데이터에 대한 다양한 조합으로 테스트 수행 org.junit.runners.Theories 실행기 사용 : @DataPoint, @DataPoints @FromDataPoints assumeXxx 수행할 테스트에는 @Test 대신 @Theory 표시 @RunWith(Theories.class) public class AdultValidationTest { @DataPoints(“uid”) public static long[] UIDS = new long[] { 10, 33, 452, 4321 }; @DataPoints(“cid”) public static long[] CIDS = new long[] { 1, 53, 100, 984, 1343 }; @Theory public void validate(@FromDataPoints("uid")long userId, @FromDataPoints("cid")long contentId){ User user = UserService.findById(userId); assumeTrue(user.isAdult()); Content content = ContentService.findById(contentId); assertTrue(content.isValid(user)); } }
  • 59.
  • 60. JUnit public class MemberJUnitWithSpringTest { AnnotationConfigApplicationContext appctx; MemberService memberService; @Before public void setUp() { appctx = new AnnotationConfigApplicationContext(Config.class); memberService = appctx.getBean(MemberService.class); } @Test public void test() throws Exception { assertEquals(memberService.getMember(1).getName(), " "); assertEquals(memberService.getMember(2).getName(), " "); assertEquals(memberService.getMember(3).getName(), " "); } @After public void teardown() { appctx.close(); } }
  • 61. 애플리케이션 컨텍스트 관리와 캐시 테스트 설비 의존관계 주입 트랜잭셕 관리 통합 테스트에 유용한 스프링의 클래스 라이브러리 제공
  • 62. @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Config.class) public class MemberJUnitWithManualSpringTest { @Autowired public MemberService memberService; @Test public void test() throws Exception { assertEquals(memberService.getMember(1).getName(), " "); assertEquals(memberService.getMember(2).getName(), " "); assertEquals(memberService.getMember(3).getName(), " "); } } SpringJUnit4ClassRunner
  • 63. @DirtiesContext public void test() throws Exception { …… } @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) public class ContextDirtyingTests { @DirtiesContext public class ContextDirtyingTests { 초기화가 오래 걸리는 애플리케이션 컨텍스트 재사용 @DirtiesContext: ,
  • 64. @Transactional을 테스트 클래스에 지정할 경우 매 테스트마다 자동으로 원복 (rollback) 처리가 됨 @TransactionConfiguration으로 빈 설정과 별도로 테스트 클래스 수준의 트 랜잭션 설정 추가 가능 @TransactionConfiguration(transactionManager = “txMgr", defaultRollback = false) @Transactional public class CustomConfiguredTransactionalTests { @Rollback로 클래스 수준의 기본 트랜잭션 설정을 메서드 단위에서 변경 가능 @Rollback(false) public void testProcessWithoutRollback() { …… } (commit)
  • 65. 트랜잭션 전후에 로직 실행 가능 @BeforeTransaction public void beforeTransaction() { …… } @AfterTransaction public void afterTransaction() { …… } public class PartiallyTransactionalTests { @Transactional public void testProcessWithTransaction(){ …… } public void testProcessWithoutTransaction(){ …… }
  • 66. @WebAppConfiguration을 지정한 테스트 클래스의 애플리케이션 컨텍스트는 WebApplicationContext가 됨 기본으로 “file:src/main/webapp"을 웹 루트 경로로 사용 웹 루트 경로를 @WebAppConfiguration의 인자로 지정 가능 MockHttpServletRequest나 MockHttpSession을 주입 받고 리퀘스트와 세 션 스코프 빈을 테스트 할 수 있음 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @WebAppConfiguration public void ScopedBeanTests() { @Autowired WebApplicationContext wac; @Autowired MockHttpServletRequest request; …… } WebApplicationContext HttpServletRequest
  • 67. MVC
  • 70. MVC 스프링 MVC 테스트 프레임워크 유창한(fluent) API로 서술적으로 테스트 조건과 단정문을 작성 서블릿 컨테이너 없이 스프링 MVC의 모든 동작과 뷰(View) 처 리 결과까지 테스트 MockMvcBuilders를 사용해서 생성 mockMvc = standaloneSetup(new AccountController()) .defaultRequest(get("/") .contextPath("/app").servletPath("/main") .accept(MediaType.APPLICATION_JSON).build(); mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); Web Application Context
  • 71. MVC @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=AppConfig.class) @WebAppConfiguration public class ControllerTest { @Autowired WebApplicationContext wac; MockMvc mockMvc; @Before public void init() { mockMvc = MockMvcBuilders.webAppContextSetup(wac) .alwaysDo(MyResultLogger.log()) .alwaysExpect(status().isOk()) .build(); } … }
  • 73. 
 (MockMvcRequestBuilders) import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; … mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON)); mockMvc.perform(fileUpload(“/doc").file(“a1", "ABC".getBytes("UTF-8"))); mockMvc.perform(get("/hotels").param("foo", "bar")); delete(), fileUpload(), get(), post(), put() 다섯 가지 HTTP 메소드별 빌더 생성 정적 메서드 제공 공통적으로 url 템플릿 기능 제공 fileUpload()는 MockMultipartHttpServletRequestBuilder 반환, 나머지는 MockHttpServletRequestBuilder 반환
  • 74. 
 (MockMvcRequestBuilders) accept(MediaType... mediaTypes) buildRequest(javax.servlet.ServletContext servletContext) characterEncoding(java.lang.String encoding) content(byte[] content) content(java.lang.String content) contentType(MediaType mediaType) contextPath(java.lang.String contextPath) cookie(javax.servlet.http.Cookie... cookies) createServletRequest(javax.servlet.ServletContext servletContext) flashAttr(java.lang.String name, java.lang.Object value) flashAttrs(java.util.Map<java.lang.String,java.lang.Object> flashAttributes) header(java.lang.String name, java.lang.Object... values) headers(HttpHeaders httpHeaders) isMergeEnabled() locale(java.util.Locale locale) merge(java.lang.Object parent) param(java.lang.String name, java.lang.String... values) pathInfo(java.lang.String pathInfo) principal(java.security.Principal principal) requestAttr(java.lang.String name, java.lang.Object value) secure(boolean secure) servletPath(java.lang.String servletPath) session(MockHttpSession session) sessionAttr(java.lang.String name, java.lang.Object value) sessionAttrs(java.util.Map<java.lang.String,java.lang.Object> sessionAttributes) with(RequestPostProcessor postProcessor)
  • 75. ContentResultMatchers content() CookieResultMatchers cookie() FlashAttributeResultMatchers flash() ResultMatcher forwardedUrl(java.lang.String expectedUrl) HandlerResultMatchers handler() HeaderResultMatchers header() <T> ResultMatcher jsonPath(java.lang.String expression, org.hamcrest.Matcher<T> matcher) JsonPathResultMatchers jsonPath(java.lang.String expression, java.lang.Object... args) ModelResultMatchers model() ResultMatcher redirectedUrl(java.lang.String expectedUrl) RequestResultMatchers request() StatusResultMatchers status() ViewResultMatchers view() XpathResultMatchers xpath(java.lang.String expression, java.util.Map<java.lang.String,java.lang.String> namespaces, java.lang.Object... args) XpathResultMatchers xpath(java.lang.String expression, java.lang.Object... args)
  • 76. • Request attribute test ( Attribute ) • .andExpect(request().attribute(.., ..)) • Session attribute test ( ) • .andExpect(request().sessionAttribute(.., ..)) • Async test ( Servlet 3.0, Spring 3.2 ) • .andExpect(request(). asyncStarted(.., ..)) • ? • .andExpect(request(). asyncNotStarted(.., ..)) • ? • .andExpect(request(). asyncResult(.., ..)) • ?
  • 77. • Handler type test ( Handler ) • .andExpect(handler().handlerType(..)) • Handler method name test ( Handler ) • .andExpect(handler().methodName(..)) • Handler method type test ( Handler ) • .andExpect(handler().method(..))
  • 78. • Model attrbute test ( Model ) • .andExpect(model().attribute(..)) • .andExpect(model().attributeExists(..)) • .andExpect(model().attributeErrorCount(..)) • .andExpect(model().attributeHasErrors(..)) • .andExpect(model().attributeHasNoErrors(..)) • .andExpect(model().attributeHasFieldErrors(..)) • .andExpect(model().errorCount(..)) • .andExpect(model().hasErrors(..)) • .andExpect(model().hasNoErrors(..))
  • 79. • Status test ( ) • .andExpect(status().is(..)) • ( 200: … ) • org.springframework.http HttpStatus • Error message test ( ) • .andExpect(status().reason(..)) • . • Header test ( ) • .andExpect(header().string(..)) • .andExpect(header().longValue(..))
  • 80. • ContentType test( contentType ) • .andExpect(content().contentType(..)) • .andExpect(content().contentTypeCompatibleWith(..)) • Encoding test ( content ) • .andExpect(content().encoding(..)) • Content test ( content ) • .andExpect(content().string(..)) : content • .andExpect(content().bytes(..)) : content byte • .andExpect(content().xml(..)) : content xml dom • .andExpect(content().node(..)) : content xml dom node • .andExpect(content().source(..)) : content xml dom source
  • 81. • View name test ( View name ) • .andExpect(view().name(..)) • Forwarded url test( URL ) • .andExpect(forwardedUrl(..)) • Redirected url test ( URL ) • .andExpect(redirectedUrl(..)) • Flash attribute test ( Spring 3.1 Flash attribute ) • .andExpect(flash().attribute(..)) : attribute • .andExpect(flash(). attributeExists(..)) : attribute • .andExpect(flash(). attributeCount(..)) : attribute
  • 83. • ? (Right-BICEP, ) - Right - ? - Boundary - correct ? - Inverse - ? - Cross-check - ? - Error condition - ? - Performance - ? • (A-trip) - Automatic (IDE, CI) - Thorough (Coverage ) - Repeatable - Independent (Fixture setting) - Professional ( )
  • 86. : -> -> : = (spec.) (Testability) : Simple Design “사전에 테스트를 고려하여 개발한게 아니다보니 억지로 테스트를 만들게 된다. 그 리고 언젠가 부터 테스트는 mocking으로 도배되거나 @Ignore가 추가되고 있다.”
  • 88. ( )
  • 90. ATDD Concordion: http://www.concordion.org/ Cucumber: http://cukes.info/ Fitnesse: http://fitnesse.org/ Selenium: http://docs.seleniumhq.org/ and JUnit… ;^)
  • 91. 100%