69
Continuous Integration 지속적인 테스트 조영호 카페PJT2008.09.16 [email protected]

Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

Continuous Integration

지속적인 테스트

조영호

카페PJT팀

2008.09.16

[email protected]

Page 2: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

1. 지속적인 테스트

2. 테스트 분류

목차

3. xUnit

Page 3: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

1. 지속적인 테스트

Page 4: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

4 / 문서의 제목

컴포넌트 A(신뢰도 90%)

컴포넌트 B(신뢰도 90%)

컴포넌트 C(신뢰도 90%)

선형 시스템의 신뢰도

신뢰도 = 0.9 x 0.9 x 0.9 = 0.73

Page 5: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

5 / 문서의 제목

신뢰할 수 있는 시스템

100%짜리(또는 그 정도에 가까운) 서비스 수준 계약서를

체결한 소프트웨어 어플리케이션을 만들고자 한다면,

반드시 개별 객체 수준에서 신뢰도를 보장해야만 할겁니다.

단위 테스트(Unit Test)

Page 6: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

6 / 문서의 제목

신뢰할 수 있는 시스템

단위 테스트를 통한 객체 수준의 신뢰도 보장

객체가 이용되는 상황을 효과적으로 재현하는 테스트 케이스 구축

테스트를 자주 실행

시스템 내 변경사항 발생 시 언제라도 테스트 실행

지속적인 테스트

Page 7: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

7 / 문서의 제목

자동화된 개발자 테스트 돌리기

피드백주기

소프트웨어품질을향상시키고위험을줄이기

| \ \

}]

{[

“‘ Integrate

?/

shift?/

P ㅖㅔ

통합하기

소스 코드컴파일하기

테스트돌리기

검사수행하기

소프트웨어배포하기

데이터베이스통합하기

Page 8: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

8 / 문서의 제목

2. 테스트 분류

Page 9: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

9 / 문서의 제목

테스트의 분류

단위 테스트

컴포넌트테스트

시스템테스트

• 소프트웨어 시스템 내의 작은 요소의 행동 검증

• 일반적으로 하나의 클래스를 테스트

기능테스트

• 소프트웨어 시스템의 일부를 테스트

•상호작용하는 컴포넌트들간의 행동 검증

• 외부 의존성 요구

완전히 설치된 시스템, DB, 파일 시스템, 네트워크 종점

• 단위 테스트보다 오래 걸림

• 전체 소프트웨어 시스템을 실행

• 완전히 설치된 시스템 요구

• 설치하는 시간이 길고 실행 시간도 김

• 테스트를 위한 설치 작업이 빌드의 일부로 포함

• 어플리케이션의 기능성을 클라이언트 관점에서 테스트

• 인수 테스트

Page 10: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

10 / 문서의 제목

테스트의 분류

데이터베이스

서버 연동 시스템

사용자

사용자

사용자

Page 11: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

11 / 문서의 제목

단위 테스트

데이터베이스

연동 시스템

사용자

사용자

사용자

서버

사용자

class

class

class

네트워크 케이블을 빼고 데이터베이스를 종료시키고 나서도 돌아

가는 테스트가 진짜 단위 테스트입니다

Page 12: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

12 / 문서의 제목

컴포넌트 테스트

사용자

사용자

사용자

서버 연동 시스템

데이터베이스

컴포넌트 수준의 테스트는 API를 통해 코드를 수행하지만, 외부

클라이언트에 노출될 때도 있고, 그렇지 않을 수도 있습니다.

Page 13: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

13 / 문서의 제목

시스템 테스트

사용자

사용자

사용자

서버 연동 시스템

데이터베이스

시스템 테스트는 웹 페이지, 웹 서비스 종점, GUI가 처음부터 끝까지

설계된 대로 작동하는지를 검증합니다.

Page 14: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

14 / 문서의 제목

기능 테스트

사용자

사용자

사용자

서버 연동 시스템

데이터베이스

어플리케이션의 기능을 클라이언트 관점에서 테스트하는 것이며, 이는 테스트

자체가 클라이언트를 흉내 낸다는 뜻입니다.

Page 15: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

15 / 문서의 제목

테스트의 분류

단위 테스트

컴포넌트테스트

시스템테스트

• 소프트웨어 시스템 내의 작은 요소의 행동 검증

• 일반적으로 하나의 클래스를 테스트

기능테스트

• 소프트웨어 시스템의 일부를 테스트

•상호작용하는 컴포넌트들간의 행동 검증

• 외부 의존성 요구

완전히 설치된 시스템, DB, 파일 시스템, 네트워크 종점

• 단위 테스트보다 오래 걸림

• 전체 소프트웨어 시스템을 실행

• 완전히 설치된 시스템 요구

• 설치하는 시간이 길고 실행 시간도 김

• 테스트를 위한 설치 작업이 빌드의 일부로 포함

• 어플리케이션의 기능성을 클라이언트 관점에서 테스트

• 인수 테스트

테스트에 필요한 설치 작업에 따라 테스트 분화

테스트 실행에 소요되는 시간과 직접적인 연관

테스트 범주화는 지속적인 통합 문맥 하에서 매우 중요

Feedback

시간이 덜 걸리는 테스트부터 실행

Page 16: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

16 / 문서의 제목

개발자 테스트를 여러 범주로 나누기

Annotation

Test Suite 구성

디렉토리 분류

src/

pom.xml

main/

test/

java/

java/

unit/

component/

system/

project/

Page 17: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

17 / 문서의 제목

개발자 테스트를 여러 범주로 나누기

Maven2 Profile 사용

<profiles>

<profile>

<id>junit</id>

<properties>

<deploy.phase>local</deploy.phase>

<settings.runEnv>test</settings.runEnv>

<maven.test.skip>false</maven.test.skip>

<log4j.runEnv>log4j.xml</log4j.runEnv>

</properties>

<build>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-surefire-plugin</artifactId>

<version>2.4.2</version>

<configuration>

<excludes>

<exclude>**/*IntegrationTest.java</exclude>

</excludes>

</configuration>

</plugin>

</plugins>

</build>

</profile>

Page 18: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

18 / 문서의 제목

3. xUnit

Page 19: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

19 / 문서의 제목

JUnit

자바 프로그래밍 언어를 위한 단위 테스팅 프레임워크

By Kent Beck and Erich Gamma

Kent Beck의 SUnit 프레임워크로부터 유래

http://www.junit.org/

xUnit Family

PHPUnit (PHP)

NUnit (C#)

PyUnit (Python)

fUnit (Fortran)

Test::Class, Test::Unit (Perl)

CPPUnit (C++)

JSUnit (JavaScript)

유사 프레임워크

TestNG

Unit

Page 20: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

20 / 문서의 제목

JUnit 3.x

이름 짓기 규약

testCreateAccount()testCreateAccDef()testCreateAcctDup()

createAccount()

TestAccount.java Account.java

Unit

Page 21: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

21 / 문서의 제목

JUnit 3.x

단정 메소드assertTrue(boolean condition)

assertFalse(boolean condition)

assertEquals(Object expected, Object actual)Uses equals() comparison

Overloaded for all primitive types

assertSame(Object expected, Object actual)

assertNotSame(Object expected, Object actual)Uses == comparison

assertEquals(float expected, float actual, float tolerance)

assertNull(Object o)

assertNotNull(Object o)

fail(String message)

TestCase

MyTestCase

Unit

Page 22: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

22 / 문서의 제목

JUnit 3.x

TestCase

MyTestCase

package org.eternity.common.money;

import junit.framework.TestCase;

public class FirstTestCase extends TestCase {

public FirstTestCase(String method) {

super(method);

}

public void testAdd() {

assertEquals(2, 1+1);

}

}

샘 플

Unit

Page 23: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

23 / 문서의 제목

JUnit 3.x

public class DatabaseTestCase extends TestCase {

private Connection dbConn;

protected void setUp() {

dbConn = new Connection("oracle", 1521,

"fred", "foobar");

dbConn.connect();

}

protected void tearDown() {

dbConn.disconnect();

dbConn = null;

}

public void testAccountAccess() {

// dbConn 사용// ......

}

public void testEmployeeAccess() {

// dbConn 사용// ......

}

}

Test FixturesetUp()

testAccountAccess()

tearDown

setUp()

testEmployeeAccess()

tearDown()

Unit

Page 24: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

24 / 문서의 제목

junit.framework

JUnit 3.x

Test Suite

<<interface>>

Test

TestCaseTestSuite

*

MyTestCase

Unit

Page 25: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

25 / 문서의 제목

JUnit 3.x

package org.eternity.common.money;

import junit.framework.Test;import junit.framework.TestCase;import junit.framework.TestSuite;

public class SecondTestCase extends TestCase {public SecondTestCase(String method) {

super(method);}

public void testSubtract() {assertTrue(10-5 > 0);

}

public void testMultiply() {assertEquals(50, 10*5);

}

public void testDivide() {assertEquals(2, 10/5);

}

public static Test suite() {TestSuite suite = new TestSuite();suite.addTest(new SecondTestCase("testMultiply"));suite.addTest(new SecondTestCase("testDivide"));

return suite;}

}

Test Suite

Unit

Page 26: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

26 / 문서의 제목

JUnit 3.x

Exception

public void testForException() {

try {

sortMyList(null);

fail("should have thrown an exception!");

} catch(NullPointerException ex) {

assertTrue(true);

}

}

Unit

Page 27: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

27 / 문서의 제목

JUnit3에서 JUnit 4로

JUnit4는 Java 5 이상을 요구

junit.framework.TestCase를 상속하지 않는 독립 클래스로 작성

org.junit.*과 org.junit.Assert.*를 importorg.junit.Assert.*에 대해 static importTestCase로부터 상속 받지 않기 때문

명명규칙을따르는메소드대신 Annotation 사용@Test는 testXXX() 메소드대체@Before는 setUp() 메소드대체@After는 tearDown() 메소드대체

@+

Unit

Page 28: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

28 / 문서의 제목

JUnit4

public class DatabaseTestCase {

private Connection dbConn;

@Before

protected void connectDB() {

dbConn = new Connection("oracle", 1521,

"fred", "foobar");

dbConn.connect();

}

@After

protected void closeDB() {

dbConn.disconnect();

dbConn = null;

}

@Test

public void checkAccountAccess() {

// dbConn 사용// ......

}

@Test

public void checkEmployeeAccess() {

// dbConn 사용// ......

}

}

Test FixtureconnectDB()

checkAccountAccess()

closeDB

connectDB()

checkEmployeeAccess()

closeDB()

Unit

Page 29: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

29 / 문서의 제목

JUnit4

package org.eternity.common.money;

import junit.framework.Test;import junit.framework.TestCase;import junit.framework.TestSuite;

public class SecondTestCase extends TestCase {public SecondTestCase(String method) {

super(method);}

public void testSubtract() {assertTrue(10-5 > 0);

}

public void testMultiply() {assertEquals(50, 10*5);

}

public void testDivide() {assertEquals(2, 10/5);

}

public static Test suite() {TestSuite suite = new TestSuite();suite.addTest(new SecondTestCase("testMultiply"));suite.addTest(new SecondTestCase("testDivide"));

return suite;}

}

Test Suite

Unit

Page 30: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

30 / 문서의 제목

JUnit4

package org.eternity.common.money;

import org.junit.runner.RunWith;

import org.junit.runners.Suite;

import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)

@SuiteClasses({FirstTestCase.class,SecondTestCase.class})

public class SimpleTestSuite{

}

Test Suite

@RunWith, @SuiteClasses

Unit

Page 31: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

31 / 문서의 제목

JUnit4

Exception

@Test(expected=NullPointerException.class)

public void checkNullParameterList() {

sortMyList(null);

}

Unit

Page 32: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

32 / 문서의 제목

Mock Object

디버깅하기 위해 사용되는 실세계 객체의 대용물

Mock Object가 유용한 경우

진짜 객체가 비결정적인 동작을 할 경우

결과 예측이 어려운 경우

진짜 객체를 준비 설정하기 어려운 경우

진짜 객체자 직접 유발시키기 어려운 동작을 하는 경우

네트워크 에러

진짜 객체가 너무 느린 경우

진짜 객체가 UI를 가지거나, UI 자체인 경우

진짜 객체에게 그것이 어떻게 사용되는지 물어봐야 하는 경우

진짜 객체가 아직 존재하지 않는 경우

Unit

Page 33: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

33 / 문서의 제목

Mock Object

Mock Object 구조

객체에 인터페이스 사용

인터페이스를 구현한 제품 코드

인터페이스를 구현한 모의 객체

Interface

MockObject

Unit

TestTarget

RealObject

Page 34: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

34 / 문서의 제목

Mock Object

Behavior Verification

테스트 대상 객체가 다른 객체와의 협력 테스트

테스트 대상 객체가 협력 객체의 메소드를 정상적으로 호출하는지 여부 검증

Mock Object는 Behavioral Verification 기법

State Verification

기존의 JUnit 기반의 단위 테스트

대상 객체의 상태 변화 체크

Unit

MockObjectObject

http://martinfowler.com/articles/mocksArentStubs.html

Mocks Aren’t Stubs By Martin Fowler

정상적으로 호출하는지 테스트

Page 35: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

35 / 문서의 제목

Mock Object

Mock Object를 실행 시간에 자동 생성

jMock

http://www.jmock.org/

EasyMock

http://www.easymock.org/

MockObject RealObject

Mock Object 자동 생성

Unit

TestCase TestTarget Interface

Page 36: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

36 / 문서의 제목

Mock Object Unit

MockObject ArticleScrappable

ScrapableCafeScrapTest CafeScrap

게시물 스크랩Test 대상 객체 네트워크를 통해 게시글 전송

네트워크가 비정상적일 경우?

Dependency Problem

Page 37: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

37 / 문서의 제목

Mock Object

jMock

@RunWith(JMock.class)

public class CafeScrapTest {

private Mockery context = new JUnit4Mockery();

private CafeScrap cafeScrap;

private Scrapable scrapable;

@Before

public void prepareCafeSrap() {

cafeScrap = new CafeScrap();

scrapable = context.mock(Scrapable.class);

cafeScrap.setScrappable(scrapable);

}

@Test

public void scrapToBlog() {

final Article article = new Article();

context.checking(new Expectations() {{

one(scrapable).scrap(article, Service.BLOG);

will(throwException(new BlogServerNotAvailableException()));

}});

assertFalse(cafeScrap.sendToBlog(article));

}

}

Expectation 설정

Behavior Verification

Scrapable 인터페이스를 구현한

Mock Object 생성

Unit

Page 38: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

38 / 문서의 제목

Mock Object

EasyMock

public class CafeScrapTest {

private CafeScrap cafeScrap;

private Scrapable scrapable;

@Before

public void prepareCafeSrap() {

cafeScrap = new CafeScrap();

scrapable = EasyMock.createMock(Scrapable.class);

cafeScrap.setScrappable(scrapable);

}

@Test

public void scrapToBlog() {

Article article = new Article();

EasyMock.expect(scrapable.scrap(article, Service.BLOG))

.andThrow(new BlogServerNotAvailableException());

EasyMock.replay(scrapable);

assertFalse(cafeScrap.sendToBlog(article));

EasyMock.verify(scrapable);

}

}

Expectation 설정

Behavior Verification

Scrapable 인터페이스를 구현한

Mock Object 생성 후 테스트 객체에연결

행동 재생

행동 검증

Unit

Page 39: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

39 / 문서의 제목

Spring Database Test Support

AbstractTransactionalSpringContextTests

org.springframework.test.AbstractTransactionalSpringContextTests

테스트 종료 후 데이터베이스 트랜잭션 롤백

getConfigLocations()스프링 빈 컨텍스트 위치 목록 반환

onSetUpBeforeTransaction()트랜잭션이 시작되기 전 호출

onSetUpInTransaction()트랜잭션이 시작된 후 호출

onTearDownInTransaction()트랜잭션이 롤백 되기 전에 호출

onTearDownAfterTransaction() 트랜잭션이 롤백된 후 호출

Component

Page 40: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

40 / 문서의 제목

Spring Database Test Support

public abstract class CafeBaseTransactionalSpringContextTests extends AbstractTransactionalSpringContextTests {

private String[] getCommonConfigLocations() {return new String[] { ConfigLocations.TEST };

}

protected abstract String[] getModuleConfigLocations();

@Overrideprotected String[] getConfigLocations() {

String[] commonConfigs = getCommonConfigLocations();

String[] moduleConfigs = getModuleConfigLocations();

String[] configs = new String[commonConfigs.length + moduleConfigs.length];for (int i = 0; i < commonConfigs.length; i++) {

configs[i] = commonConfigs[i];}

for (int i = 0; i < moduleConfigs.length; i++) {int j = commonConfigs.length + i;configs[j] = moduleConfigs[i];

}

return configs;}

CafeBaseTransactionalSpringContextTests

Component

Page 41: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

41 / 문서의 제목

@Override

protected void onSetUpBeforeTransaction() throws Exception {

ContextHolder.setAttribute(

CafeConstants.CONTEXTHOLDER_MULTIPLEDBKEY,

new MultipleDBKeyInfo(getMultipleDBKey(), true));

SqlMapPlugIn plugIn = new SqlMapPlugIn();

plugIn.init(null);

}

/**

* CLUBBBS나 CAFEINFO db를 사용하는 경우에는 무조건 이 메소드를 override해야 한다.

* @return

*/

protected Integer getMultipleDBKey() {

return null;

}

}

Spring Database Test Support

CafeBaseTransactionalSpringContextTests

Component

Page 42: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

42 / 문서의 제목

Spring Database Test Support

Custom Test Case

public class TemplateMovieDAOImplTest

extends CafeBaseTransactionalSpringContextTests {

private TemplateMovieDAO templateMovieDAO;

private Integer TEST_CLUBID = 10141287;

@Override

protected String[] getModuleConfigLocations() {

return new String[]{ConfigLocations.DAO_BOARD,

ConfigLocations.TEST_CLUBBBS

};

}

protected Integer getMultipleDBKey() {

return TEST_CLUBID;

}

public void setTemplateMovieDAO(TemplateMovieDAO templateMovieDAO) {

this.templateMovieDAO = templateMovieDAO;

}

public void testSelect() {

// DAO를 사용한 테스트 코드// ......

}

/META-INF/applicationContext-common-dao-board.xml

/META-INF/applicationContext-common-test-clubbbs.xml

Component

Page 43: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

43 / 문서의 제목

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="transactionManager"

class="com.naver.cafe.common.transaction.CafeTransactionManager">

<property name="dbKey">

<bean

id="com.naver.cafe.common.dao.DBKeyGenerator.DB_KEY_CLUBBBS"

class="org.springframework.beans.factory.config

.FieldRetrievingFactoryBean" />

</property>

</bean>

</beans>

Spring Database Test Support

Transaction Manager 설정

applicationContext-common-test-clubbbs.xml

clubbbs

conf/datasource/datasource-clubbbs.xml

Component

Page 44: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

44 / 문서의 제목

DbUnit

데이터베이스 Component Testing 툴

테스트 간에 데이터베이스를 알려진 상태로 유지하기 위해 사용

테스트 데이터를 자동으로 데이터베이스에 입력

테스트 종료 후 테스트 이전으로 자동 복귀

http://www.dbunit.org/

DbUnit Best Practices

개발자 한 명 당 하나의 데이터베이스 인스턴스 사용

테스트를 정상적으로 설정한 경우 클린업 절차 불필요

하나의 거대한 데이터 셋 대신 여러 개의 작은 데이터 셋 사용

전체 테스트 클래스나 테스트 스위트에 대해 현행화된 데이터를 사용할 것

Component

Page 45: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

45 / 문서의 제목

DbUnit

테스트 라이프 사이클

테스트 데이터

데이터베이스

초기화

테스트 코드

테스트 코드

테스트 코드

Component

Page 46: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

46 / 문서의 제목

DbUnit

테스트 라이프 사이클

테스트 데이터

데이터베이스

테스트 코드

테스트 코드

테스트 코드

Component

Page 47: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

47 / 문서의 제목

DbUnit

테스트 라이프 사이클

테스트 데이터

데이터베이스

테스트 코드

테스트 코드

테스트 코드

실행

데이터 변경

Component

Page 48: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

48 / 문서의 제목

DbUnit

테스트 라이프 사이클

테스트 데이터

데이터베이스

테스트 코드

테스트 코드

테스트 코드

데이터베이스

복구

Component

Page 49: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

49 / 문서의 제목

DbUnit

테스트 라이프 사이클

테스트 데이터

데이터베이스

초기화

테스트 코드

테스트 코드

테스트 코드

Component

Page 50: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

50 / 문서의 제목

DbUnit

테스트 라이프 사이클

테스트 데이터

데이터베이스

테스트 코드

테스트 코드

테스트 코드

Component

Page 51: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

51 / 문서의 제목

DbUnit

테스트 라이프 사이클

테스트 데이터

데이터베이스

테스트 코드

테스트 코드

테스트 코드

데이터 변경

Component

Page 52: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

52 / 문서의 제목

DbUnit

Cafe 프로젝트용 DbUnit 커스터마이징

bridge 프로젝트의 com.naver.cafe.unit 패키지

다중 DB 지원

카페 DB별 테스트 데이터 초기화 기능 지원

전체 테이블이 아닌 결과 XML에 명시된 데이터만 검증 가능

,초기 데이터 PK를 사용하여 테스트 데이터 제거

MyTestCase

AbstractDependencyInjectionSpringContextTests

CafeTestCase

Component

Page 53: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

53 / 문서의 제목

DbUnit

<?xml version="1.0" encoding="UTF-8"?>

<dataset>

<CLT_ARTICLE clubid="14446632" articleid="158" menuid="2" subject="제목"

content="테스트용 게시물" writerid="baejjae93" writernickname="baejjae93"

writedt="2008-02-14" refarticleid="14446632" replylistorder="“

readcount="0" commentcount="0" refarticlecount="0" lastcommentdate="[null]"

type="[null]" openyn="Y" replyyn="Y" scrapyn="Y"

attachimageyn="[null]" attachfileyn="[null]" attachpollyn="[null]"

attachmovie="0" scrapcount="0" scrapedyn="[null]" accesslevel="0"

personacon="0" font="" leveragecode="39" searchopen="1" rclick="0"

hastag="0" blockyn="0" modifydt="[null]" spamscore="0"

gdid="99999999_99999999999999999999999" headid="[null]“

blockstatus="[null]" ccl="0" autosourcing="0" templatecode="[null]"/>

<CFT_LEVERAGE_ARTICLE clubid="14446632" articleid="158" leveragecode="39"

leveragepk="[null]" categoryname="[null]" srcurl="[null]"

srcurlhtml="[null]" commentcount="[null]" status="L"

modifydate="[null]" adddate="2008-02-14" userip="172.0.0.1"/>

<CFT_LEVERAGE_THEME clubid="14446632" articleid="158" leveragecode="39"

theme="내 책"/>

</dataset>

테스트 데이터

Component

Page 54: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

54 / 문서의 제목

DbUnit

<?xml version="1.0" encoding="UTF-8"?>

<dataset>

<CFT_LEVERAGE_ARTICLE TEST_CASE_INDEX="1"

clubid="14446632" articleid="158" leveragecode="39"

leveragepk="120" categoryname="categoryresult"

srcurl="http://dev.book.naver.com/bookdb/book_detail.php?bid=2925556"

srcurlhtml="[null]" commentcount="[null]" status="O"

userip="172.0.0.1"/>

<CFT_LEVERAGE_ARTICLE TEST_CASE_INDEX="2"

clubid="14446632" articleid="158" leveragecode="39“

leveragepk="[null]" categoryname=""

srcurlhtml="[null]" commentcount="[null]" status="L"

userip="172.0.0.1"/>

<CFT_LEVERAGE_ARTICLE TEST_CASE_INDEX="3"

clubid="14446632" articleid="158" leveragecode="39“

leveragepk="" categoryname=""

srcurlhtml="[null]" commentcount="0" status="R"

userip="172.0.0.1"/>

<CFT_LEVERAGE_THEME clubid="14446632" articleid="158" leveragecode="39"

theme="내 책"/>

</dataset>

결과 데이터

Component

Page 55: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

55 / 문서의 제목

public class ApplyOperationIntegrationTest extends CafeTestCase {

@Override

protected String[] getCafeConfigLocations() {

return new String [] {

"/META-INF/applicationContext-bridge-bo.xml",

......

"/META-INF/applicationContext-bridge-leverage.xml"

};

}

@Override

protected Integer getClubId() {

return 14446632;

}

@Override

protected void afterSetUp() throws Exception {

loadDataSet(DBKeyGenerator.DB_KEY_CLUB,

"ApplyOperationIntegrationTest-club-setup.xml");

loadDataSet(DBKeyGenerator.DB_KEY_CLUBBBS,

"ApplyOperationIntegrationTest-clubbbs-setup.xml");

}

DbUnit

Custom Test Case

어플리케이션 컨텍스트 로드

데이터베이스 선택을 위해 오버라이딩

테스트 데이터 로드

Component

Page 56: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

56 / 문서의 제목

public void testApplySuccessOnNormalQueue() throws Exception {

HttpClientInvokerStub httpClientInvokerStub = new HttpClientInvokerStub("1",

FailureCause.NO_FAILURE.name(), "120",

"http://dev.book.naver.com/bookdb/book_detail.php?bid=2925556",

"categoryresult");

((LeverageRequestSenderImpl)getBean("leverageRequestSenderTarget"))

.setHttpClientInvoker(httpClientInvokerStub);

LeverageRequest leverageRequest = LeverageRequestBuilder.apply(getClubId(),

Leveraged.before(getArticleId(), LeverageEnum.BOOK.getCode()));

assertTrue(cafeToVerticalProducerBO.sendDirectly(leverageRequest));

verify(DBKeyGenerator.DB_KEY_CLUBBBS,

"ApplyOperationIntegrationTest-clubbbs-result.xml", 1);

}

DbUnit

Custom Test Case

결과 테스트 데이터를 사용하여

데이터 베이스 상태 검증

Component

Page 57: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

57 / 문서의 제목

HTTPUnit

웹 어플리케이션 System Testing Tool

웹어플리케이션용테스트스크립트 구현

JUnit 기반프레임웍

http://httpunit.sourceforge.net/

System

Page 58: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

58 / 문서의 제목

HTTPUnit

public class CaclHttpTestCase {

@Test

public void calc() throws Exception {

WebConversation conversation = new WebConversation();

WebRequest request = new GetMethodWebRequest(

"http://127.0.0.1:8080/calc.action?added=10&addend=20");

WebResponse response = conversation.getResponse(request);

assertEquals(30,

Integer.parseInt(response.getElementWithID("result").getText()));

}

HTTPUnit Test Case

System

Page 59: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

59 / 문서의 제목

@Test

public void calcUsingForm() throws Exception {

WebConversation conversation = new WebConversation();

WebRequest request = new GetMethodWebRequest(

"http://127.0.0.1:8080/calcView.action");

WebResponse response = conversation.getResponse(request);

WebForm form = response.getFormWithName("calc");

form.setParameter("addend", "100");

form.setParameter("added", "20");

response = form.submit();

assertEquals(120,

Integer.parseInt(response.getElementWithID("result").getText()));

}

}

HTTPUnit

HTTPUnit Test Case

System

Page 60: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

60 / 문서의 제목

JWebUnit

웹 어플리케이션 System Testing Tool

웹어플리케이션용테스트스크립트 구현

HTTPUnit 기반

JUnit 기반프레임웍

특징

웹 애플리케이션검색에쓰이는고급 API 제공

링크를통한네비게이션

폼 엔트리와제출

테이블내용

assertion 집합포함

http://httpunit.sourceforge.net/

System

Page 61: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

61 / 문서의 제목

JWebUnit

public class CaclHttpTestCase {

private WebTester webTester;

@Before

public void initTestContext() {

webTester = new WebTester();

webTester.getTestContext().setBaseUrl("http://127.0.0.1:8080/");

}

@Test

public void calc() throws Exception {

webTester.beginAt("/calc.action?added=10&addend=20");

webTester.assertElementPresent("result");

webTester.assertTextInElement("result", "30");

}

JWebUnit Test Case

System

Page 62: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

62 / 문서의 제목

JWebUnit

@Test

public void calcUsingForm() throws Exception {

webTester.beginAt("/calcView.action");

webTester.setWorkingForm("calc");

webTester.setTextField("addend", "100");

webTester.setTextField("added", "20");

webTester.submit();

webTester.assertElementPresent("result");

webTester.assertTextInElement("result", "120");

}

}

JWebUnit Test Case

System

Page 63: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

63 / 문서의 제목

Selenium

웹 어플리케이션을 위한 Acceptance Testing 툴

테스트를 HTML 테이블로 작성

http://selenium.openqa.org/

Selenium IDE

FireFox 플러그인

Test Case Record & Replay 기능제공

Selenium-RC(Remote Control)

프로그래밍언어를사용하여 Acceptance Test 작성및실행가능

Server

브라우저를자동으로실행하고웹요청을처리하는 Proxy

Client

프로그램작성을위한클라이언트라이브러리

Functional

Page 64: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

64 / 문서의 제목

Selenium

Selenium IDE

Functional

Page 65: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

65 / 문서의 제목

Selenium

Selenium IDE

Functional

Page 66: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

66 / 문서의 제목

Selenium

Selenium-RC

Functional

Page 67: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

67 / 문서의 제목

Selenium

Selenium-RC와 JUnit 통합

Selenium IDE의 Test Case Export 기능을 사용하여 생성

public class CalcAcceptTestCase extends SeleneseTestCase {

public void setUp() throws Exception {

setUp("http://localhost:8080/", "*iexplore");

}

public void testCalc() throws Exception {

selenium.open("/calc.action?added=10&addend=20");

assertTrue(selenium.isTextPresent("30"));

assertEquals("30", selenium.getText("result"));

}

public void testCalcView() throws Exception {

selenium.open("/calcView.action");

selenium.type("added", "100");

selenium.type("addend", "20");

selenium.click("//input[@value='계산']");

assertEquals("120", selenium.getText("result"));

}

}

Functional

Page 68: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

Thank you.

Page 69: Continuous Integration 지속적인테스트pds17.egloos.com/pds/201002/17/18/4.Continuous_Test.pdf · 테스트의분류 단위테스트 컴포넌트테스트 시스템테스트

Question.