SlideShare uma empresa Scribd logo
1 de 45
테스트 가능한
소프트웨어 설계와
TDD작성 패턴
Testable software design & TDD patterns




                         한국 스프링 사용자 모임 (KSUG )

                                          채수원
발표자 개
발 자 소개
LG CNS 경영기술교육원 기술교육팀 전임강사

강의 과목
디자인 패턴 & 리팩터링
분석설계 실무
Agile
A il 적용실무

블로그
여름으로 가는 문 blog.doortts.com



Comments
  내용이나 후기에 대해서는 Outsider님의 후기
  (http://blog.outsider.ne.kr/494) 를 참조 하시면
  (htt //bl      t id      k /494)
  좀 더 도움이 될 겁니다.
흠
흠…

     Comments
       2010년 7월 10일 화창한 토요일 오후 이대 ECC
Why are we here?
보다 더 나은 소프트웨어와
 다         웨어와
보다 더 나은 삶을 만들기 위해
객체 지향 기본 원칙
OCP
SRP
ISP
Demeter s
Demeter’s Law (=hollywood law)
              ( hollywood
IOC
        Comments
        언어도 열심히 배우고 원칙도 학습했으니까 개발을 더 잘할 수 있겠죠?
다음 두 코드 중 더 나은 디자인은?
 Case.1   class Rental {
              Movie movie;
              Rental(Service service) {
                  this.movie = service.getMovie();
              }
          }

 Case.2
 C    2   class R t l {
                Rental
              Movie movie;
              Rental(Movie movie) {
                  this.movie = movie;
              }
          }
(based on my five years of educational experience)

Strongly recommended approach #1
St    l          d d        h




               테스트 주도 개발
               Test-Driven D
               T t Di      Development
                               l     t
TDD 관점에서 바라봤을 때 드러나는



     안 좋은 디자인의 징후
      - 단위 테스트 케이스 작성이 어렵다
      - 단위 테스트 케이스가 자주 깨진다
                       깨진다.
      - 단위 테스트 케이스 실행을 위한 준비해야 할 것이 많다.
      - 다른 사람의 테스트 케이스를 읽기가 어렵다.
강형 마이크로 디자인
기초 점검 코스
“프로그램을 작성하기 전에 테스트 먼저 하라!”
 프로그램을                하라!
Test the program before you write it.




“잘 동작하는 깔끔한 코드”
 잘
Clean code that works




“질문
 질             응답            정
                             정제         반복
                                        반복”
Ask     Respond     Refine    Repeat
p
public class Calculator {
  public int sum(int a, int b) {
    return 0;
  }

    public static void main(String[] args) {
        Calculator calc = new Calculator();
        System.out.println( calc.sum(10, 20) == 30 );
        System.out.println( calc.sum(1, 2) == 3 );
        System.out.println( calc.sum(-10, 20) == 10 );
        S            i l ( l        ( 10            )
        System.out.println( calc.sum(0, 0) == 0 );
    }
}                 모두 true면 작성완료!

-----실행 결과-----
     실행 결과
false
false
false       Comments
true       굳이 프레임워크를 쓰지 않아도 무방합니다. 업무로직 작성 전에 완성상태를
              검증해 줄 수 있는 코드가 존재하기만 하면 충분합니다.
기본 코스
생성자 메소드 테스트
(
(constructor method test)
                        )

 public class E l
   bli l      EmployeeDaoTest {
                      D T t

 @Test
 public EmployeeDaoTest {
     EmployeeDao d = new E l
     E l     D dao         EmployeeDao();
                                    D ()
     assertTrue(dao.isConnected());
 }
동치 비교
( q
(equivalence test)
                 )

@Test
public void testEquals_case2() {
    Music musicA = new M i ("BAD" "Mi h l")
       i     i         Music("BAD", "Michael");
    Music musicB = new Music("BAD", "Michael");
    assertEquals ( musicA musicB);
                   musicA,
}
동치 비교
( q
(equivalence test)
                 )
해결책.1
해결책 1   내부 상태(보통은 필드값)를 직접 꺼내와서 각각
        비교한다.
해결책.2   toString을 중첩구현해(override)놓고, toString 값
        으로 비교한다.

해결책.3   equals 메소드를 중첩구현한다.

해결책.3   Unitils의 assertReflectionEquals를 이용한다.
배열비교
(
(array test)
     y     )
해결책.1
해결책 1   JUnit 4의 assertArrayEquals를 이용한다
                                    이용한다.


해결책.2   Unitils의 assertReflectionEquals나
        assertLenientEquals를 이용한다

해결책.3   List로 변환해서 비교한다.
배열비교
(
(array test)
     y     )

@Test
public void testArrayEqual_NotSorted() {
    String[] arrayA = new String[] {"A", "B", "C"};
                                   { A    B    C };
    String[] arrayB = new String[] {"B", "A", "C"};
    Arrays.sort
    Arrays sort (arrayA);
    Arrays.sort (arrayB);
    assertArrayEquals (arrayA, arrayB);
}
몇 가지 오해
boolean isRight(){
    return TDD == UnitTest
}
(Do) All or Noting
단위 테스트 케이스 작성
Skeleton vs Incremental
      package main;
      public class Account {

          public Account(int i) {
          }
          public i
            bli int getBalance() {
                          l    ()
              return 0;
          }
          public void withdraw(){
          }
          public void deposit(){
          }
      }
One method one assert ?
  @Test
  public void testGetBalance() throws Exception {
    bli    id          l    () h            i
      assertEquals (10000, account.getBalance());
      account = new Account(1000);

      assertEquals (1000, account.getBalance());
      account = new Account(0);

      assertEquals (0, account.getBalance());
  }
Anti-pattern
Anti pattern
      private Account account;

      @Before
      public void setUp(){
          account = new Account(10000);
      }

      @Test
      public void testWithdraw() throws Exception {
          account.withdraw(1000);
                          (    )
          assertEquals(9000, account.getBalance());
      }
Anti-pattern
    public     class AccountTest {

            @Before
            public void setUp(){
            }

            @Test
            p
            public void testDeposit() throws Exception {
                              p    ()            p
                Account account = new Account(10000);
                account.deposit(1000);
                assertEquals(11000, account.getBalance());
            }

            @Test
            public void testWithdraw() throws Exception {
                Account account = new Account(10000);
                account.withdraw(1000);
                assertEquals(9000, account.getBalance());
                          l (                   l     ())
        }
    }
단위 테스트 접근 방식
상태기반 테스트
                 입력



       methodA


           doSomething



            ?


     예상결과
          = 실제결과
상태기반 테스트

 @Test
 public void t tFil R
             testFileRemove() {
                           ()
     FileUtile fileUtil = new FileUtil();
     fileUtil.cleanContents( targetFile );
     assertEquals( 0 fileUtil size( targetFile ) );
                   0, fileUtil.size(
 }
행위기반 테스트
  Case.1
  Case 1      입력A


           methodA               methodB


            doSomething          rampOn




  Case.2      입력B


           methodA
                                 methodB

                          call
           doSomething
           d S   thi                 rampOn
                                         O
행위기반 테스트

@Test
public void testGetOrderPrice () throws Exception {
    PriceCalculator calculator = new PriceCalculator();
    Item item = new Item("LightSavor","Kitchen knife",100000);
    ICoupon coupon = new Coupon();
    assertEquals(93000, calculator.getOrderPrice(item, coupon));
    int methodCallCount = ((Coupon)coupon).getIsAppliableCallCount();
    assertEquals (1, methodCallCount);
}
행위기반 테스트
public class Coupon implements ICoupon {

    private int isAppliableCallCount;
    @Override
    public boolean isAppliable(Item item) {
        isAppliableCallCount++; // 호출되면 증가
                                     출
         ……..
    }

    p
    public int getIsAppliableCallCount(){
               g     pp               (){
        return this.isAppliableCallCount;
    }
}
행위기반 테스트

@Test
p
public void testGetOrderPrice () throws Exception {
                                            p
    PriceCalculator calculator = new PriceCalculator();
    Item item = new Item("LightSavor","Kitchen knife",100000);
                    Item( LightSavor   Kitchen knife 100000);
    ICoupon mockCoupon = mock(ICoupon.class);
        … // mocking 작업
    assertEquals(93000, calculator.getOrderPrice(item, mockCoupon));
    verify (
       if (mockCoupon, ti
              kC       times(1)).isAppliable(box);
                            (1)) i A li bl (b );
}
TDD with Spring
  스프링 프레임워크의 Unit Test 지원
    링 레임워 의


     - 의존관계 주입을 통한 객체 생성
     - 웹 컨테이너 없는 웹 애플리케이션 테스트
     - 단위 테스트 지원 유틸리티


                   => Injection과 Mock
XmlBeanFacotry로 컨텍스트 가져오는 버전
             y   텍
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi http://www.w3.org/2001/XMLSchema instance
        xmlns:xsi="http://www w3 org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http //www.springframework.org/schema/beans/spring beans.xsd >
        http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="music" class="main.MP3">
    <constructor-arg value="Belong to me.mp3"/>
                   g             g        p
  </bean>
  <bean id="musicPlayer" class="main.MusicPlayer">
    <property name="music" ref="music"/>
  </bean>
</beans>


XmlBeanFactory beanFactory
  = new XmlBeanFactory(
      new ClassPathResource("/context-musicplayer xml")
          ClassPathResource( /context musicplayer.xml )
     );
Unitils를 사용

 @RunWith(UnitilsJUnit4TestClassRunner class)
 @RunWith(UnitilsJUnit4TestClassRunner.class)
 public class UnitilsMusicPlayerTest {

     @SpringApplicationContext( /context-musicplayer.xml )
     @SpringApplicationContext("/context-musicplayer xml")
     private ApplicationContext context;
 …
 …
 }
annotation및 autowire를 사용해서

@RunWith(SpringJUnit4ClassRunner class)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/context-musicplayer.xml"})
public class AutowiredMusicPlayerTest {

    @Autowired
    MusicPlayer player;
…
…
}
Injection기능만 사용할 경우
Google Guice(쥬스)로 처리해 보면

static Injector injector = Guice.createInjector(new MusicModule());

@Test
public void testGetFileName() throws Exception {
    MusicPlayer player = injector.getInstance(MusicPlayer.class);
    assertEquals("Belong To Me.mp3", player.getFileName());
}
TDD with Spring – servlet test




           이름     박성철
           사번     5874

           아이디    fupfin

           직위     회장
TDD with Spring – servlet test
public class EmployeeSearchServletTest {
@Test
public void testSearchByEmpid() throws Exception {
  bli    id      S   h     id() h            i
    MockHttpServletRequest request = new MockHttpServletRequest(); // ➊
    MockHttpServletResponse response = new MockHttpServletResponse(); // ➋
    request.addParameter("empid", "5874") // ➌
             ddP        ("   id" "5874");

    EmployeeSearchServlet searchServlet
        = new EmployeeSearchServlet(); // ➍
    searchServlet.service(request, response); // ➎

    Employee employee = (Employee)request getAttribute("employee"); // ➏
                        (Employee)request.getAttribute( employee );

    assertEquals ("박성철", employee.getName() ); // ➐
    assertEquals ("5874", employee getEmpid() );
                 ( 5874   employee.getEmpid()
    assertEquals ("fupfin", employee.getId() );
    assertEquals ("회장", employee.getPosition() );
    assertEquals( /SearchResult.jsp ,
    assertEquals("/SearchResult.jsp", response.getForwardedUrl()); // ➑
    }
}
발표를 마치며
Q&A
    감사합니다

doortts@gmail.com
이미지 참조
Longing for Summer
http://www.flickr.com/photos/68165632@N00/1553091251/

Coupling sketches cropped
http://www.flickr.com/photos/49432745@N03/4533798684/

Tagged, finally...
http://www.flickr.com/photos/kornrawiee/3189034267/

Vincent Boiteau
 i         i
http://www.flickr.com/photos/2dogs_productions

Mais conteúdo relacionado

Mais procurados

Testing RESTful Webservices using the REST-assured framework
Testing RESTful Webservices using the REST-assured frameworkTesting RESTful Webservices using the REST-assured framework
Testing RESTful Webservices using the REST-assured frameworkMicha Kops
 
API Testing following the Test Pyramid
API Testing following the Test PyramidAPI Testing following the Test Pyramid
API Testing following the Test PyramidElias Nogueira
 
Testing RESTful web services with REST Assured
Testing RESTful web services with REST AssuredTesting RESTful web services with REST Assured
Testing RESTful web services with REST AssuredBas Dijkstra
 
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드SangIn Choung
 
Getting started with karate dsl
Getting started with karate dslGetting started with karate dsl
Getting started with karate dslKnoldus Inc.
 
Automação e virtualização de serviços
Automação e virtualização de serviçosAutomação e virtualização de serviços
Automação e virtualização de serviçosElias Nogueira
 
Rest api 테스트 수행가이드
Rest api 테스트 수행가이드Rest api 테스트 수행가이드
Rest api 테스트 수행가이드SangIn Choung
 
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 SangIn Choung
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practicesnickokiss
 
Test your microservices with REST-Assured
Test your microservices with REST-AssuredTest your microservices with REST-Assured
Test your microservices with REST-AssuredMichel Schudel
 
Les dessous du framework spring
Les dessous du framework springLes dessous du framework spring
Les dessous du framework springAntoine Rey
 
Karate for Complex Web-Service API Testing by Peter Thomas
Karate for Complex Web-Service API Testing by Peter ThomasKarate for Complex Web-Service API Testing by Peter Thomas
Karate for Complex Web-Service API Testing by Peter Thomasintuit_india
 
Space Camp June 2022 - API First.pdf
Space Camp June 2022 - API First.pdfSpace Camp June 2022 - API First.pdf
Space Camp June 2022 - API First.pdfPostman
 
Criando uma arquitetura para seus testes de API com RestAssured
Criando uma arquitetura para seus testes de API com RestAssuredCriando uma arquitetura para seus testes de API com RestAssured
Criando uma arquitetura para seus testes de API com RestAssuredElias Nogueira
 

Mais procurados (20)

Testing RESTful Webservices using the REST-assured framework
Testing RESTful Webservices using the REST-assured frameworkTesting RESTful Webservices using the REST-assured framework
Testing RESTful Webservices using the REST-assured framework
 
Rest assured
Rest assuredRest assured
Rest assured
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 
API Testing following the Test Pyramid
API Testing following the Test PyramidAPI Testing following the Test Pyramid
API Testing following the Test Pyramid
 
Testing RESTful web services with REST Assured
Testing RESTful web services with REST AssuredTesting RESTful web services with REST Assured
Testing RESTful web services with REST Assured
 
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
katalon studio 툴을 이용한 GUI 테스트 자동화 가이드
 
Getting started with karate dsl
Getting started with karate dslGetting started with karate dsl
Getting started with karate dsl
 
Java8 features
Java8 featuresJava8 features
Java8 features
 
Automação e virtualização de serviços
Automação e virtualização de serviçosAutomação e virtualização de serviços
Automação e virtualização de serviços
 
Rest api 테스트 수행가이드
Rest api 테스트 수행가이드Rest api 테스트 수행가이드
Rest api 테스트 수행가이드
 
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드 Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
Postman과 Newman을 이용한 RestAPI 테스트 자동화 가이드
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practices
 
Test your microservices with REST-Assured
Test your microservices with REST-AssuredTest your microservices with REST-Assured
Test your microservices with REST-Assured
 
Test Complete
Test CompleteTest Complete
Test Complete
 
Les dessous du framework spring
Les dessous du framework springLes dessous du framework spring
Les dessous du framework spring
 
Karate for Complex Web-Service API Testing by Peter Thomas
Karate for Complex Web-Service API Testing by Peter ThomasKarate for Complex Web-Service API Testing by Peter Thomas
Karate for Complex Web-Service API Testing by Peter Thomas
 
Space Camp June 2022 - API First.pdf
Space Camp June 2022 - API First.pdfSpace Camp June 2022 - API First.pdf
Space Camp June 2022 - API First.pdf
 
Criando uma arquitetura para seus testes de API com RestAssured
Criando uma arquitetura para seus testes de API com RestAssuredCriando uma arquitetura para seus testes de API com RestAssured
Criando uma arquitetura para seus testes de API com RestAssured
 
Using Mockito
Using MockitoUsing Mockito
Using Mockito
 
Mockito
MockitoMockito
Mockito
 

Destaque

테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)KH Park (박경훈)
 
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자Taeyeop Kim
 
Amazon ECS를 통한 도커 기반 콘테이너 서비스 구축하기 - AWS Summit Seoul 2017
Amazon ECS를 통한 도커 기반 콘테이너 서비스 구축하기 - AWS Summit Seoul 2017Amazon ECS를 통한 도커 기반 콘테이너 서비스 구축하기 - AWS Summit Seoul 2017
Amazon ECS를 통한 도커 기반 콘테이너 서비스 구축하기 - AWS Summit Seoul 2017Amazon Web Services Korea
 
콘테이너 운영을 위한 Amazon EC2 Container Service(ECS) 집중 분석
콘테이너 운영을 위한 Amazon EC2 Container Service(ECS) 집중 분석콘테이너 운영을 위한 Amazon EC2 Container Service(ECS) 집중 분석
콘테이너 운영을 위한 Amazon EC2 Container Service(ECS) 집중 분석Amazon Web Services Korea
 
Tdd 왜 배우기 어려운가
Tdd 왜 배우기 어려운가Tdd 왜 배우기 어려운가
Tdd 왜 배우기 어려운가Jaehoon Oh
 

Destaque (6)

테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)테스트 자동화와 TDD(테스트 주도 개발방법론)
테스트 자동화와 TDD(테스트 주도 개발방법론)
 
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자IoT 개발자를 위한 Embedded C에서 TDD를 해보자
IoT 개발자를 위한 Embedded C에서 TDD를 해보자
 
Amazon ECS를 통한 도커 기반 콘테이너 서비스 구축하기 - AWS Summit Seoul 2017
Amazon ECS를 통한 도커 기반 콘테이너 서비스 구축하기 - AWS Summit Seoul 2017Amazon ECS를 통한 도커 기반 콘테이너 서비스 구축하기 - AWS Summit Seoul 2017
Amazon ECS를 통한 도커 기반 콘테이너 서비스 구축하기 - AWS Summit Seoul 2017
 
콘테이너 운영을 위한 Amazon EC2 Container Service(ECS) 집중 분석
콘테이너 운영을 위한 Amazon EC2 Container Service(ECS) 집중 분석콘테이너 운영을 위한 Amazon EC2 Container Service(ECS) 집중 분석
콘테이너 운영을 위한 Amazon EC2 Container Service(ECS) 집중 분석
 
AWS DevDay 실습 가이드 - 콘테이너
AWS DevDay 실습 가이드 - 콘테이너AWS DevDay 실습 가이드 - 콘테이너
AWS DevDay 실습 가이드 - 콘테이너
 
Tdd 왜 배우기 어려운가
Tdd 왜 배우기 어려운가Tdd 왜 배우기 어려운가
Tdd 왜 배우기 어려운가
 

Semelhante a 테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)

자바 테스트 자동화
자바 테스트 자동화자바 테스트 자동화
자바 테스트 자동화Sungchul Park
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기Heo Seungwook
 
10장 결과 검증
10장 결과 검증10장 결과 검증
10장 결과 검증dagri82
 
120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장tedypicker
 
데이터베이스패턴
데이터베이스패턴데이터베이스패턴
데이터베이스패턴Suan Lee
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블YongEun Choi
 
Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Ji Ung Lee
 
Python Unittest
Python UnittestPython Unittest
Python Unittest명규 최
 
[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개Jong Pil Won
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트YongEun Choi
 
[하코사 세미나] 비전공자의 자바스크립트 도전기
[하코사 세미나] 비전공자의 자바스크립트 도전기 [하코사 세미나] 비전공자의 자바스크립트 도전기
[하코사 세미나] 비전공자의 자바스크립트 도전기 인권 김
 
Python 테스트 시작하기
Python 테스트 시작하기Python 테스트 시작하기
Python 테스트 시작하기Hosung Lee
 
08장 객체와 클래스 (기본)
08장 객체와 클래스 (기본)08장 객체와 클래스 (기본)
08장 객체와 클래스 (기본)유석 남
 
TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDSuwon Chae
 
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...Ryan Park
 
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅NAVER D2
 
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 HowRyan Park
 

Semelhante a 테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD) (20)

자바 테스트 자동화
자바 테스트 자동화자바 테스트 자동화
자바 테스트 자동화
 
Tdd 4장
Tdd 4장Tdd 4장
Tdd 4장
 
C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기C++ 프로젝트에 단위 테스트 도입하기
C++ 프로젝트에 단위 테스트 도입하기
 
10장 결과 검증
10장 결과 검증10장 결과 검증
10장 결과 검증
 
120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장120908 레거시코드활용전략 4장5장
120908 레거시코드활용전략 4장5장
 
데이터베이스패턴
데이터베이스패턴데이터베이스패턴
데이터베이스패턴
 
Effective unit testing ch3. 테스트더블
Effective unit testing   ch3. 테스트더블Effective unit testing   ch3. 테스트더블
Effective unit testing ch3. 테스트더블
 
Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Refactoring - Chapter 8.2
Refactoring - Chapter 8.2
 
Spring Boot 2
Spring Boot 2Spring Boot 2
Spring Boot 2
 
Python Unittest
Python UnittestPython Unittest
Python Unittest
 
[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개[2011 04 11]mock_object 소개
[2011 04 11]mock_object 소개
 
시작하자 단위테스트
시작하자 단위테스트시작하자 단위테스트
시작하자 단위테스트
 
[하코사 세미나] 비전공자의 자바스크립트 도전기
[하코사 세미나] 비전공자의 자바스크립트 도전기 [하코사 세미나] 비전공자의 자바스크립트 도전기
[하코사 세미나] 비전공자의 자바스크립트 도전기
 
Python 테스트 시작하기
Python 테스트 시작하기Python 테스트 시작하기
Python 테스트 시작하기
 
08장 객체와 클래스 (기본)
08장 객체와 클래스 (기본)08장 객체와 클래스 (기본)
08장 객체와 클래스 (기본)
 
JUnit & AssertJ
JUnit & AssertJJUnit & AssertJ
JUnit & AssertJ
 
TDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDDTDD&Refactoring Day 03: TDD
TDD&Refactoring Day 03: TDD
 
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...Agd   Test Driven Development For Games What, Why, And How)(Game Connect 2006...
Agd Test Driven Development For Games What, Why, And How)(Game Connect 2006...
 
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
 
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
 

Mais de Suwon Chae

실패한 프로젝트들의 개발문화_개발방법론
실패한 프로젝트들의 개발문화_개발방법론실패한 프로젝트들의 개발문화_개발방법론
실패한 프로젝트들의 개발문화_개발방법론Suwon Chae
 
TDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDDTDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDDSuwon Chae
 
TDD&Refactoring Day 01: Refactoring
TDD&Refactoring Day 01: RefactoringTDD&Refactoring Day 01: Refactoring
TDD&Refactoring Day 01: RefactoringSuwon Chae
 
Ryan Dahl의 Node.js 소개 동영상 해설 by doortts
Ryan Dahl의 Node.js 소개 동영상 해설 by doorttsRyan Dahl의 Node.js 소개 동영상 해설 by doortts
Ryan Dahl의 Node.js 소개 동영상 해설 by doorttsSuwon Chae
 
Mongo db로 배우는 nosql
Mongo db로 배우는 nosqlMongo db로 배우는 nosql
Mongo db로 배우는 nosqlSuwon Chae
 
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)Suwon Chae
 

Mais de Suwon Chae (7)

실패한 프로젝트들의 개발문화_개발방법론
실패한 프로젝트들의 개발문화_개발방법론실패한 프로젝트들의 개발문화_개발방법론
실패한 프로젝트들의 개발문화_개발방법론
 
Refactoring
RefactoringRefactoring
Refactoring
 
TDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDDTDD&Refactoring Day 02: TDD
TDD&Refactoring Day 02: TDD
 
TDD&Refactoring Day 01: Refactoring
TDD&Refactoring Day 01: RefactoringTDD&Refactoring Day 01: Refactoring
TDD&Refactoring Day 01: Refactoring
 
Ryan Dahl의 Node.js 소개 동영상 해설 by doortts
Ryan Dahl의 Node.js 소개 동영상 해설 by doorttsRyan Dahl의 Node.js 소개 동영상 해설 by doortts
Ryan Dahl의 Node.js 소개 동영상 해설 by doortts
 
Mongo db로 배우는 nosql
Mongo db로 배우는 nosqlMongo db로 배우는 nosql
Mongo db로 배우는 nosql
 
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
잘하면고효율, 못하면가문의원수가되는 짝프로그래밍 (Effective Pair Programming with Lessons Learned)
 

테스트 가능한 소프트웨어 설계와 TDD작성 패턴 (Testable design and TDD)

  • 1. 테스트 가능한 소프트웨어 설계와 TDD작성 패턴 Testable software design & TDD patterns 한국 스프링 사용자 모임 (KSUG ) 채수원
  • 2. 발표자 개 발 자 소개 LG CNS 경영기술교육원 기술교육팀 전임강사 강의 과목 디자인 패턴 & 리팩터링 분석설계 실무 Agile A il 적용실무 블로그 여름으로 가는 문 blog.doortts.com Comments 내용이나 후기에 대해서는 Outsider님의 후기 (http://blog.outsider.ne.kr/494) 를 참조 하시면 (htt //bl t id k /494) 좀 더 도움이 될 겁니다.
  • 3. 흠 흠… Comments 2010년 7월 10일 화창한 토요일 오후 이대 ECC
  • 4. Why are we here?
  • 5. 보다 더 나은 소프트웨어와 다 웨어와 보다 더 나은 삶을 만들기 위해
  • 7. OCP SRP ISP Demeter s Demeter’s Law (=hollywood law) ( hollywood IOC Comments 언어도 열심히 배우고 원칙도 학습했으니까 개발을 더 잘할 수 있겠죠?
  • 8. 다음 두 코드 중 더 나은 디자인은? Case.1 class Rental { Movie movie; Rental(Service service) { this.movie = service.getMovie(); } } Case.2 C 2 class R t l { Rental Movie movie; Rental(Movie movie) { this.movie = movie; } }
  • 9. (based on my five years of educational experience) Strongly recommended approach #1 St l d d h 테스트 주도 개발 Test-Driven D T t Di Development l t
  • 10. TDD 관점에서 바라봤을 때 드러나는 안 좋은 디자인의 징후 - 단위 테스트 케이스 작성이 어렵다 - 단위 테스트 케이스가 자주 깨진다 깨진다. - 단위 테스트 케이스 실행을 위한 준비해야 할 것이 많다. - 다른 사람의 테스트 케이스를 읽기가 어렵다.
  • 13. “프로그램을 작성하기 전에 테스트 먼저 하라!” 프로그램을 하라! Test the program before you write it. “잘 동작하는 깔끔한 코드” 잘 Clean code that works “질문 질 응답 정 정제 반복 반복” Ask Respond Refine Repeat
  • 14. p public class Calculator { public int sum(int a, int b) { return 0; } public static void main(String[] args) { Calculator calc = new Calculator(); System.out.println( calc.sum(10, 20) == 30 ); System.out.println( calc.sum(1, 2) == 3 ); System.out.println( calc.sum(-10, 20) == 10 ); S i l ( l ( 10 ) System.out.println( calc.sum(0, 0) == 0 ); } } 모두 true면 작성완료! -----실행 결과----- 실행 결과 false false false Comments true 굳이 프레임워크를 쓰지 않아도 무방합니다. 업무로직 작성 전에 완성상태를 검증해 줄 수 있는 코드가 존재하기만 하면 충분합니다.
  • 16. 생성자 메소드 테스트 ( (constructor method test) ) public class E l bli l EmployeeDaoTest { D T t @Test public EmployeeDaoTest { EmployeeDao d = new E l E l D dao EmployeeDao(); D () assertTrue(dao.isConnected()); }
  • 17. 동치 비교 ( q (equivalence test) ) @Test public void testEquals_case2() { Music musicA = new M i ("BAD" "Mi h l") i i Music("BAD", "Michael"); Music musicB = new Music("BAD", "Michael"); assertEquals ( musicA musicB); musicA, }
  • 18. 동치 비교 ( q (equivalence test) ) 해결책.1 해결책 1 내부 상태(보통은 필드값)를 직접 꺼내와서 각각 비교한다. 해결책.2 toString을 중첩구현해(override)놓고, toString 값 으로 비교한다. 해결책.3 equals 메소드를 중첩구현한다. 해결책.3 Unitils의 assertReflectionEquals를 이용한다.
  • 19. 배열비교 ( (array test) y ) 해결책.1 해결책 1 JUnit 4의 assertArrayEquals를 이용한다 이용한다. 해결책.2 Unitils의 assertReflectionEquals나 assertLenientEquals를 이용한다 해결책.3 List로 변환해서 비교한다.
  • 20. 배열비교 ( (array test) y ) @Test public void testArrayEqual_NotSorted() { String[] arrayA = new String[] {"A", "B", "C"}; { A B C }; String[] arrayB = new String[] {"B", "A", "C"}; Arrays.sort Arrays sort (arrayA); Arrays.sort (arrayB); assertArrayEquals (arrayA, arrayB); }
  • 22. boolean isRight(){ return TDD == UnitTest }
  • 23. (Do) All or Noting
  • 25. Skeleton vs Incremental package main; public class Account { public Account(int i) { } public i bli int getBalance() { l () return 0; } public void withdraw(){ } public void deposit(){ } }
  • 26. One method one assert ? @Test public void testGetBalance() throws Exception { bli id l () h i assertEquals (10000, account.getBalance()); account = new Account(1000); assertEquals (1000, account.getBalance()); account = new Account(0); assertEquals (0, account.getBalance()); }
  • 27. Anti-pattern Anti pattern private Account account; @Before public void setUp(){ account = new Account(10000); } @Test public void testWithdraw() throws Exception { account.withdraw(1000); ( ) assertEquals(9000, account.getBalance()); }
  • 28. Anti-pattern public class AccountTest { @Before public void setUp(){ } @Test p public void testDeposit() throws Exception { p () p Account account = new Account(10000); account.deposit(1000); assertEquals(11000, account.getBalance()); } @Test public void testWithdraw() throws Exception { Account account = new Account(10000); account.withdraw(1000); assertEquals(9000, account.getBalance()); l ( l ()) } }
  • 30. 상태기반 테스트 입력 methodA doSomething ? 예상결과 = 실제결과
  • 31. 상태기반 테스트 @Test public void t tFil R testFileRemove() { () FileUtile fileUtil = new FileUtil(); fileUtil.cleanContents( targetFile ); assertEquals( 0 fileUtil size( targetFile ) ); 0, fileUtil.size( }
  • 32. 행위기반 테스트 Case.1 Case 1 입력A methodA methodB doSomething rampOn Case.2 입력B methodA methodB call doSomething d S thi rampOn O
  • 33. 행위기반 테스트 @Test public void testGetOrderPrice () throws Exception { PriceCalculator calculator = new PriceCalculator(); Item item = new Item("LightSavor","Kitchen knife",100000); ICoupon coupon = new Coupon(); assertEquals(93000, calculator.getOrderPrice(item, coupon)); int methodCallCount = ((Coupon)coupon).getIsAppliableCallCount(); assertEquals (1, methodCallCount); }
  • 34. 행위기반 테스트 public class Coupon implements ICoupon { private int isAppliableCallCount; @Override public boolean isAppliable(Item item) { isAppliableCallCount++; // 호출되면 증가 출 …….. } p public int getIsAppliableCallCount(){ g pp (){ return this.isAppliableCallCount; } }
  • 35. 행위기반 테스트 @Test p public void testGetOrderPrice () throws Exception { p PriceCalculator calculator = new PriceCalculator(); Item item = new Item("LightSavor","Kitchen knife",100000); Item( LightSavor Kitchen knife 100000); ICoupon mockCoupon = mock(ICoupon.class); … // mocking 작업 assertEquals(93000, calculator.getOrderPrice(item, mockCoupon)); verify ( if (mockCoupon, ti kC times(1)).isAppliable(box); (1)) i A li bl (b ); }
  • 36. TDD with Spring 스프링 프레임워크의 Unit Test 지원 링 레임워 의 - 의존관계 주입을 통한 객체 생성 - 웹 컨테이너 없는 웹 애플리케이션 테스트 - 단위 테스트 지원 유틸리티 => Injection과 Mock
  • 37. XmlBeanFacotry로 컨텍스트 가져오는 버전 y 텍 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi http://www.w3.org/2001/XMLSchema instance xmlns:xsi="http://www w3 org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http //www.springframework.org/schema/beans/spring beans.xsd > http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="music" class="main.MP3"> <constructor-arg value="Belong to me.mp3"/> g g p </bean> <bean id="musicPlayer" class="main.MusicPlayer"> <property name="music" ref="music"/> </bean> </beans> XmlBeanFactory beanFactory = new XmlBeanFactory( new ClassPathResource("/context-musicplayer xml") ClassPathResource( /context musicplayer.xml ) );
  • 38. Unitils를 사용 @RunWith(UnitilsJUnit4TestClassRunner class) @RunWith(UnitilsJUnit4TestClassRunner.class) public class UnitilsMusicPlayerTest { @SpringApplicationContext( /context-musicplayer.xml ) @SpringApplicationContext("/context-musicplayer xml") private ApplicationContext context; … … }
  • 39. annotation및 autowire를 사용해서 @RunWith(SpringJUnit4ClassRunner class) @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"/context-musicplayer.xml"}) public class AutowiredMusicPlayerTest { @Autowired MusicPlayer player; … … }
  • 40. Injection기능만 사용할 경우 Google Guice(쥬스)로 처리해 보면 static Injector injector = Guice.createInjector(new MusicModule()); @Test public void testGetFileName() throws Exception { MusicPlayer player = injector.getInstance(MusicPlayer.class); assertEquals("Belong To Me.mp3", player.getFileName()); }
  • 41. TDD with Spring – servlet test 이름 박성철 사번 5874 아이디 fupfin 직위 회장
  • 42. TDD with Spring – servlet test public class EmployeeSearchServletTest { @Test public void testSearchByEmpid() throws Exception { bli id S h id() h i MockHttpServletRequest request = new MockHttpServletRequest(); // ➊ MockHttpServletResponse response = new MockHttpServletResponse(); // ➋ request.addParameter("empid", "5874") // ➌ ddP (" id" "5874"); EmployeeSearchServlet searchServlet = new EmployeeSearchServlet(); // ➍ searchServlet.service(request, response); // ➎ Employee employee = (Employee)request getAttribute("employee"); // ➏ (Employee)request.getAttribute( employee ); assertEquals ("박성철", employee.getName() ); // ➐ assertEquals ("5874", employee getEmpid() ); ( 5874 employee.getEmpid() assertEquals ("fupfin", employee.getId() ); assertEquals ("회장", employee.getPosition() ); assertEquals( /SearchResult.jsp , assertEquals("/SearchResult.jsp", response.getForwardedUrl()); // ➑ } }
  • 44. Q&A 감사합니다 doortts@gmail.com
  • 45. 이미지 참조 Longing for Summer http://www.flickr.com/photos/68165632@N00/1553091251/ Coupling sketches cropped http://www.flickr.com/photos/49432745@N03/4533798684/ Tagged, finally... http://www.flickr.com/photos/kornrawiee/3189034267/ Vincent Boiteau i i http://www.flickr.com/photos/2dogs_productions