보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

개발/자바 | Posted by 은우 아빠 2008. 10. 1. 16:26

JUnit 을 이용한 단위 테스트


유난히도 "버그"를 많이 발생시키는 프로그래밍 패턴때문에, 난 "버그양성소" 역할을 해왔었다. 그동안은 main() 메소드를 통해 클래스와 메소드를 테스트했는데, 그동안의 무식함을 반성하고자 제일 기본적인 JUnit에 대해서 알아보았다.

1. JUnit 이 뭐지?
JUnit 은 테스트 프레임워크 (툴) 이다.
한마디로, 정해진 형식에따라 test 메소드를 작성해 놓으면 자동으로 실행시켜주고 결과도 리턴해주는 놈이다.

그럼 기존 java 애플리케이션 [public static void main(String[] args)] 을 이용한 테스트와는 뭐가 다른가?
정해진 방법대로 작성해 놓으면  테스트 java 애플리케이션 안의 메소드를 호출하지 않아도 자동 실행해주기 때문에, 손이 덜 간다. 그리고, 테스트 Java 애플리케이션이 많을때 이것을 일일이 실행해야 테스트를 해야하는 반면, JUnit은 TestSuit 이라는 개념을 지원해 여러개의 Test 클래스들을 한꺼번에 실행해 볼수 있다.

2. JUnit 을 사용하려면 ?
다운로드 및 참고자료 : http://junit.sourceforge.net/

junit.jar 를 classpath에 추가 하기만 하면 된다.
Eclipse 에는 기본 플러그인으로 설치되어 있어 바로 사용가능하다.

3. 코드 작성법
  1) JUnit의 TestCase 를 상속하여 클래스를 생성한다.
  2) 메소드 실행전 초기화 부분은 setUp() 메소드에, 실행후 초기화는 tearDown() 에 기술한다.
  3) 각각의 테스트할 단위들을 testXXXXX() 로 작성한다.
  4) 각 메소드에 assertXXXX() 메소드를 삽입하여, 테스트의 성공 유무를 판가름한다.
      아래 조건을 만족하지 않으면 실패로 간주
         ex) assertEquals  : 같지 않으면 실패,

assertEquals - 같은지 비교
assertNull - null값을 리턴하는지 비교
assertNotNull - 인자로 넘겨받은 객체가 null인지 판정하고 반대인경우 실패로 처리한다.
assertSame - assertSame 은 expected 와 actual이 같은 객체를 참조하는지 판정하고
                       그렇지 않다면 실패로 처리한다.
assertNotSame - expected 와 actual이 서로 '다른' 객체를 참조하는지 판정하고, 만약
                       같은 객체를 참조한다면 실패로 처리한다.
assertTrue - boolean 조건이 참인지 판정한다. 만약 조건이 거짓이라면 실패로 처리한다.
fail - 테스트를 바로 실패 처리한다.

  
4. 코드샘플과 실행결과
   1) 코드 샘플

import junit.framework.TestCase;
import com.ilikeclick.fw.util.*;

public class testUtilClass extends TestCase
{
    private String testStr1 = null;
    private String testStr2 = null;
      
    public void setUp()
    {
        System.out.println("setUp()");
    }
   
    public void tearDown()
    {
        System.out.println("tearDown()\n");
       
        testStr1 = null;
        testStr2 = null;
    }
   
    public void testCryptUtility()
    {
        System.out.println("testCryptUtility()");
       
        testStr1 = "sokum";
        testStr2 = CryptUtility.encrypt(testStr1, 3);
       
        assertNotNull(testStr2);
        assertEquals(testStr1, CryptUtility.decrypt(testStr2, 2));
    }
   
    public void testRandomUtility()
    {
        System.out.println("testRandomUtility()");       
       
        for(int loopCnt=0; loopCnt < 128; loopCnt++)
        {
            testStr1 = RandomUtility.createNumAlphaCode(loopCnt);
           
            assertNotNull(testStr1);
        }
    }
}


  2) 콘솔 - 실행결과

사용자 삽입 이미지


 








  3) JUnit 결과창
사용자 삽입 이미지



위에서는 testCryptUtility() 에서 테스트가 실패하게 비밀키를 다른게 설정했다. 참고로, CryptUtility 는 시져알고리즘을 구현한 클래스로 비밀키를 이용하여 암호화와 복호화를 지원한다.

JUnit 결과창을 보면, 실행갯수와 오류와 실패 갯수, 실행시간, 실패에 대한 추적을 한눈에 볼수 있다.

  4) 테스할 Class에 대한 TestCase 코드 자동생성하기

  이클립스에서, 테스트하고 싶은 클래스에 마우스 오른쪽 버튼을 누르고 JUnit 테스트 코드를 생성하면, 선택된 클래스의 모든 메소드를 테스트 가능하도록 껍질코드(?)를 만들어 준다.

  5) TestCase 한꺼번에 실행하기

  이러한 TestCase 를 한대에 묶어서, TestSuit 을 만들어 한꺼번에 실행해 볼 수 있다. 추가로 테스트할 TestCase 는 // $JUnit-BEGIN$ 과 // $JUnit-END$ 사이에 클래스이름을 추가해주면 된다.

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

public class AllTests
{
    public static Test suite()
    {
        TestSuite suite = new TestSuite("Test for com.ilikeclick.fw.test");
        // $JUnit-BEGIN$
        suite.addTestSuite(testUtilClass.class);
        // $JUnit-END$

        return suite;
    }
}

5. JUnit 을 적용하면 좋은점
  1) Eclipse에 기본으로 플러그인이 포함되어 있어 사용이 쉽다.
  2) JUnit 은 단위테스트의 개념을 초기확립(?) 시킨 놈으로써의 의의와 범용적으로 사용하고 있다.
  3) TestSuit 을 제공함으로써 여러개의 TestCase 클래스를 한번에 실행시킬수 있다.

6. 불편한 점
  1) 메소드 실행전후에 초기화를 담당하는 setUp(), tearDown() 메소드에 사용자 파라메터를 넘길수 없어
      불편하다.
  2) 반드시 TestCase 를 상속해야 하기땜에, 단일상속의 제한이 있는 Java 에서는 다양한 테스트가 불가능
     하다. +_+ 제일 불편한 부분이 아닐까 싶다.
     물론, JUnit 이 다른 클래스나 다른 모듈에 의존성 없이독립적으로 실행되어야 한다는 점은 십분 이해가
     가지만, 그렇다고 확장성마저 없애버린것은 좀 오버인듯 싶다.
     (그래서 다른 테스트 플랫폼도 나오고 있지만...)
  3) Servlet 은 어떻게 테스트하지? +_+;; 물론, 더 찾아봐야 알겠지만 Servlet은 어떻게 해야 할지 감이 안온다.

* JUnit 을 둘러보며 느낀점
  1) 결국 JUnit 은 형태를 정해놓고, 그 방법대로 코드를 작성하면 자동으로 메소드를 실행해주는 역할 밖에
      하지 않을정도로 간단한 놈이다.
  2) 라이브러리를 지원하지 않아도 Reflection 을 사용하면 금방 구현할것 같다. 결국 어떤사람이 먼저
     아이디어를 떠올리고 그것을 실행으로 옮기느냐에 따라 선도자가 될수도 있고, 흐름에 따르는 순응자가
     될수도 있다는 것을 다시 한번 느꼈다.
  3) 버그가 줄어들겠지? 가 아니라, 테스트 메소드를 호출하기에 편할것같다.  
     버그 날만한 것을 testXX() 메소드에 기술하여 테스트하는건 기존과 똑같으므로 결국 프로그래머에 달렸다.
     단, 누가 보더라도 메소드의 의도가 명확하고, 모든 메소드에 대하여 testXXX() 메소드를 반드시 작성해야
     함으로 작성자가 아닌 다른 프로그래머가 해당 메소드를 사용할때 "샘플코드" 로써의 역할도 수행할 수 있
     어 편할 듯 싶다.

예전 프로젝트에서 공통업무를 맡으면서 수많은 버그들을 만들어, 본인이나 쓰는 사람이나 서로 스트레스를 많이 받았었다. 이젠 개발 5년차다. 그만큼 단단한 코드 작성이 필요한 시점이 아닐까 싶다.

작성       : 남경식 / 2008-01-02 / isokum@hotmail.com


개발/소프트웨어공학 | Posted by 은우 아빠 2008. 10. 1. 16:06

클래스 다이어그램



본 호에서는 UML에서 시스템의 정적인 부분을 주로 나타내는 클래스 다이어그램을 알아볼 것이다. 독자들이 객체 지향 공부를 하면서 익힌 클래스, 상속 등의 익숙한 개념이 많이 나타나는 다이어그램이다.  UML의 다이어그램 중 어느 한 다이어그램이 중요하지 않다 말할 수는 없지만 클래스 다이어그램은 그 중 중요하다 할 수 있는 다이어그램이다. 필자가 시스템을 구축하면서 느낀 점을 보태어서 말한다면 만들어진 시스템의 정적구조가 엉망이라면 시스템의 구축이나 기능확장의 어려움이 막대하다 할 수 있다. 반면에 잘 만들어진 구조를 가졌다면 시스템 구축자체에서나 기능의 확장에 있어서 무리 없이 가능해진다.  물론 이렇게 잘 된 정적 구조의 중요성을 실감하기 위해서는 실제 시스템의 만들어보고 잘못된 구조로 인한 피해를 느껴봐야만 할 것이다.
만약 이 글을 읽는 독자 중에 시스템의 정적인 구조를 처음 설계하려는 사람이 있다면 되도록이면 빠른 싸이클로 반복을 하기 바란다.  왜냐하면  설계에 대한 충분한 경험을 가지고 있지 않고는 처음 설계한 구조가 시스템을 구축하기에 완벽하게 만족시키지 못하기 때문이다.  빠른 싸이클의 반복은 잘못된 구조의 수정 기회를 늘인다.
이제 클래스 다이어그램에 관한 내용을 알아보도록 하자. 실제 클래스 다이어그램의 내용은 한 회에 다 실을 수 없을 만큼 양이 많다.  글의 제목에서도 느낄 수 있는 것과 같이 클래스 다이어그램을 2내지3회의 분량으로 할 계획이다. 클래스 다이어그램이 이렇게 분량이 많은 이유는 클래스 다이어그램이 프로그래밍 언어들과 가장 직접적으로 연관을 맺고 있고 또한 아주 많은 부분에서 객체지향의 이론이 녹아들어가 있기 때문이다. 이번 호에서는 클래스 다이어그램의 가장 기본이 되는 요소들과  그 의미를 알아보도록 할 것이다.
1.클래스
그림 1 - 클래스의 표기
클래스의 표기는 그림1에서의 표기와 같이한다. 그림1의 좌측에 있는 것은 Attribute와 Operation이 축약되지 않은 표기이고 나머지는 축약된 표기이다.
클래스의 의미는 일반적으로 객체지향 언어에서 사용하는 클래스의 의미와 유사하다. 클래스라는 것은 시스템에서 동작하게 되는 하나의 개념의 추상화 도구로써 사용되며 추상화의 단계에 따라 클래스의 의미가 약간씩 차이가 생긴다. 만약 설계 당시에 추상화가 아주 높은 단계에서 이러한 클래스는 시스템에서 사용되는 하나의 역할로서의 의미를 가진다. 하지만 구현단계와 같은 추상화 단계가 아주 낮은 상태에서는 실제 객체를 생성하기 위한 클래스의의미를 가지게 된다. 이러한 단계의 구별은 사용자의 의도에 따라 적당히 사용하면 될 것이다.
2.Attribute와 Operation
Attribute와 Operation 의 표기 또한 추상화 단계에 따라 표기의 방법이 달라 질 수 있다. 예를 들어 구현단계에 근접하여 클래스 다이어그램을 도시하려 한다면 구현하기위한 언어에 밀접한 형태의 Attribute와 Operation 으로 나타내어야 하지만 추상화 단계가 높을 경우는 대략적인 의미 전달을 할 수 있을 정도로 표기하여도 된다. Attribute의 UML1.1 표준형식은 다음과 같다.
visibility name : type-expression = initial-value { property-string }.
구조에 대한 설명은 프로그래밍 언어를 사용하여 본 사람이라면 쉽게 이해할 수 있을 것이다. Operation의 UML1.1표준형식은 다음과 같다.
visibility name ( parameter-list ) : return-type-expression { property-string }
Attribute와 마찬가지고 구조는 쉽게 이해될 것이다. 여기서 한가지 짚고 넘어가야 할 부분이 Visibility부분이다. 언어에서 Visibility를 private와 protect, public으로 구분하듯이 여기서도 이러한 구분을 표시할 수 있다. 즉 private는 '-'로 protected 는 '#'로 public은 '+'로 표기함을 알아두어야 할 것이다.
3.클래스와 클래스의 상속관계(Generalization Relationship).
그림 2  - 상속관계
상속관계의 표기는 그림 2와 같이 닫혀져 있는 머리를 가진 화살표로 나타낸다.
상속의 의미는 일반 언어에서의 상속의 의미와 유사하게 상위클래스의 모든 특징과 행위를 하위의 클래스가 모두 이어받게 된다. 즉 다양한 클래스들의 나열에서 동일한 행위나 특징을 가진 여러 클래스들이 존재할 때 공통되는 부분을 상위 클래스로 만들 수 있다.

4.클래스와 클래스의 연관관계(Association Relationship)
그림 3 - 연관관계
연관관계의 표기는 그림 3과 같이 실선으로 표기하게 된다. 연관관계의 의미는 두 클래스가 서로 어떠한 연관을 가지고 있다는 의미이다.  예를 들어 회사와 사원은 어떤 식으로든지 연관을 가지고 있다. 이것을 표현하기 위해서 연관의 관계를 사용한다. 물론 이러한 연관을 사용하기 위해서 UML에서는 표기의 확장으로 여러가지 장식(Adornments)들을 사용한다 여기서 사용되는 장식들로는 연관의 이름, 다중성(Multiplicity), 역할이름(RoleName) 등이 있다. 각 장식에 대하여 알아보면 먼저 연관의 이름은 어떠한 연관인지를 명시적으로 나타내게 된다. 다중성의 의미는 연관된 상대의 수를 표시하게 된다. 마지막으로 역할이름은 연관을 맺은 상태에서 상대 클래스에서 사용되어지게 되는 역할의 이름을 나타낸다.
5.클래스와 클래스의 집합연관관계(Aggregation Relationship)
그림 4 - 집합연관관계
집합연관관계의 표기는 그림 4와 같이 속이 빈 마름모 머리를 가진 실선으로 표기하게 된다. 집합연관관계는 연관관계의 일종으로 연관관계에서 쓰이는 모든 장식들이 다 쓰일 수 있다.집합연관관계를 쓰는 경우는 클래스와 클래스의 관계가 부분과 전체의 관계를 가질 때 표시할 수 있다. 예를 들면 자동차와 바퀴는 전체와 부분의 관계가 될 수 있다.
6.클래스와 클래스의 복합연관관계(Composition Relationship)
그림 5 -복합 연관관계
복합연관의 표기는 그림 5에서와 같이 속이 찬 마름모머리를 가진 실선으로 표기하게 된다. 복합 연관관계는 집합연관관계와 유사하게 전체와 부분의 관계를 나타내게 된다. 하지만 엄연한 차이점이 존재한다. 집합연관관계에서는 부분 클래스가 전체 클래스와 같은 생명시간을 가진다는 것이다. 즉 전체의 클래스의 객체가 소멸될 때 부분 클래스의 객체 또한 소멸되는 것이다. 예를 들어 우리가 흔히 말하는 윈도우를 전체로 보고 그 안에 들어가는 버튼을 부분으로 보면 이해가 쉬울 것이다.
7.클래스와 클래스의 의존관계(Dependency Relationship)
그림 6 - 의존 관계
의존관계은 그림 6에서와 같인 열려진 머리의 화살표를 가진 점선으로 표기한다.
의존관계의 의미는 한 클래스의 변화가 다른 클래스에 영향을 미칠 때 사용한다. 이러한 의존의 관계는 여러가지 관계에서 나타날 수 있다.  의존관계의 종류에 관하여서는 다음 호에 자세히 다루도록 할 것이다.
이로서 클래스 다이어그램에서 사용되는 기본적인 요소들을 모두 알아보았다. 여기서 설명한 요소들은 가장 기본적인 개념들이므로 숙지하길 바란다. 다음호 에는 이를 바탕으로 여러가지 부가적인 요소들을 알아보도록 할 것이다.

본 회에서는 지난 호에 이어 클래스 다이어그램에 나타나는 표기에 관하여 알아본다. 지난회에서 핵심이되는 클래스의 대략적인 모습을 보았다. 이번 회에는 클래스 표기 자체의 확장과 스테레오 타입을 이용한 확장된 의미의 여러가지 클래스들에 대하여 알아보기로 한다.
1. 클래스에서 사용자 정의 구역(User-defined compartment)
그림 1 사용정의 구역 (user-defined compartment)
클래스를 구성하는 부분으로 이름구역, Attribute구역, Operation구역이 있음을 우리는 알고 있다. 이러한 클래스를 구성하는 세가지 부분은 UML에서 미리 정의하는 부분이고 이외에 사용자가 정의하여 작성할 수 있는 새로운 구역을 첨가할 수 있다. 이러한 사용자 정의 구역은 툴이 제공하는 환경에 따라 다양하게 제공된다. 만약 독자 여러분이  UML Modeling툴을 만든다면 사용자 정의 역역을 이용하여 순공학이나 문서화 등의 툴의 부가적인 기능을 돋보이게 할 수 있을 것이다.
2. Type and Implementation Class
그림2  type and implementation class
지금부터 언급하는 내용은 클래스 다이어그램에 적용함에 있어서 스테레오타입(Stereotype)이나 컨스트레인트(Constraint)를 이용하여 기존 클래스의 의미를 확대하는 부분이다. 이러한 의미의 확대는 실제 업무에서 사용되는 개념과 좀 더 근접시키기위해 UML에서 표준으로 지정하고 있다.
먼저 Type의 경우 스테레오타입으로 'type'을 가진다. 이것은 객체가 가지는 Specification만을 표시한다. 그러한 이유로 실제로 언어에 바인딩되는 attribute나 method를 적는 것이 아니라 specification상에 나타나는 attribute나 operation이 반영된다. 반면에 Implementation class의 경우 실제 물리적인 언어에 바인딩되게 표현을 한다. Implementation class의 경우 스테레오 타입을 'implementationClass'를 기입하게 된다. Type과 iplementation class의 차이는 type을 실체화(Realization) 시킨 것이 Implementation class가 된다.
3. Interface
그림 3 Interface
인터페이스 클래스의 경우 스테레오타입을 'interface'로 가지며 객체지향 언어인 java에서 사용되는 인터페이스의 의미와 동일하게 클래스의 행위만을 확정하고 있다. 이러한 인터페이스는 구현을 가지지 않으므로 abstract operation을 가지게 된다.
4. Parameterized Class (Template Class)
그림 4 Parameterized Class
Parameterrized Class의 표기는 위의 그림과 같이 표기하고 그 의미는 객체지향언어 C++에서 사용되는 Template와 동일하다.
5. Utility
그림 5  Utility Class
Utility class의 표기는 스테레오타입을 'utility'로 가진다. 그 의미는 일반적인 클래스의 의미가 아니라 프로그램의 편리를 위해 만들어진 클래스이다. 프로그램을 하면 반드시 Global로 만들어야 할 프로시져나 변수들이 존재하게 된다. 이를 기능적으로 분리하기 위해 utility class를 사용한다. Utility class 내부에 존재하는 attribute나 operation의 경우 Global 변수나 프로시져로 인식하면 된다.
6. MetaClass
MetaClass의 표기는 스테레오타입을 'metaclass'로 가지는 클래스이다. 이것은 metaclass의 인스턴스가 클래스가 되는 클래스를 의미한다.
7. Enumeration
Enumeration Class의 경우 스테레오타입을 'enumeration'으로 가지는 클래스이다. Enumeration Class의 의미는 프로그램언어에서 사용되는 일반적인 enumeration type과 의미가 유사하다. 정확한 Enumeration Class의 의미는 이 클래스의 인스턴스는 반드시 사용자가 정의한 특정 문자의 집합이어야 한다는 것이다. 이러한 문자는 상대적인 순서를 가지게 된다.
8. Stereotype
Stereotype Class의 경우 UML에서 사용되는 의미확장의 도구인 stereotype을 UML에서 지정한 것 이외에 사용자 정의 스테레오타입을 만들기위해 사용되는 클래스이다. Stereotype Class의 표기는 스테레오타입을 'stereotype'으로 가진다.
9. Class Pathname
그림 6 Class Pathname
클래스를 표기함에 있어서 UML에서 패키지(Package)를 같이 붙여 클래스의 범위를 지정할 수 있다. 패키지는 UML에서 Namespace역할을 한다. 패키지에 대한 자세한 설명은 차후 다이어그램에서 공통으로 사용되는 요소를 설명할 때 하기로 한다. 패키지속에 패키지가 포함 될 수 있으므로 패키지 path를 다 적용하여 클래스의 Pathname을 표기하기도 한다.
지금까지 클래스 다이어그램에서 정의하는 확장된 의미의 표기를 살펴보았다. 참고로 이러한 모든 내용에 대하여서 자세히 알고 싶다면 UML Spec을 보는 것이 도움이 될것이다.
실무에서는 시스템을 구성하는 클래스를 뽑아내고 그것의 역할을 지정하고 연관을 맺는 것이 가장 힘든 일일 것이다. 이것에 대한 정확히 정립된 방법은 존재하지 않는다. 약간이나마 정형화된 클래스를 뽑아내는 시점에 관하여 적어보면 통상 시스템 구축에 있어서 유스케이스 다이어그램을 그려서 시스템의 큰 기능을 만들고 그 유스케이스의 흐름을 가지고 시퀀스나 콜레버레이션 다이어그램에서 객체와 객체사이의 인터렉션을 정의하게 된다. 여기서 사용되는 객체의 행위와 속성을 가지고 클래스의 구체적 형상을 뽑아낼 수 있을 것이다. 물론 여러 번의 반복을 통한 클래스이 확정이 필요할 것이다.
그 동안 필자 주변의 일로 몇 회의 뉴스레터에 글을 올리지 못한 경우가 있었습니다. 매번 이러한 이야기를 하는 것이 구차한 변명인 줄 알고 있지만 어쩔 수 없이 양해를 구해야하는 것이 도리이기에 차후에 적어나갈 글을 더욱 알차게 적겠다는 말로 사과를 대신하려 합니다.
개발/소프트웨어공학 | Posted by 은우 아빠 2008. 10. 1. 16:04

유스케이스(Usecase) 다이어그램


지난 회에서 우리는 UML의 전체 구성에 대하여 알아보았다. 전체적인 구성을 보았으니 앞으로 각 다이어그램을 하나씩 보도록 하자.  이번 회에는 유스케이스 다이어그램에 관하여 알아보도록 하겠다.  많은 다이어그램 중에 왜 유스케이스 다이어그램을 가장 먼저 설명을 하는가에 대한 의문이 일것이다.  물론 필자의 마음일 수도 있지만 이 보다도 더 명확한 이유가 존재한다.  독자 여러분이 어떠한 방법론을 배우고 있다 하더라도 프로젝트를 수행함에 있어서 가장 먼저 수행되는 일이 동일할 것이다. 그것은 프로젝트가 무엇인지에 대한 기술이다. 프로젝트가 무엇인지 모르고 어떻게 프로젝트를 수행하겠는가?  이렇게 프로젝트가 무엇인지에 대해서 알아보는 것이 요구분석(Requirement Analysis)이다.  글의 흐름으로 보아 유스케이스 다이어그램이 요구분석을 위한 다이어그램이라는 것을 유추할 수 있을 것이다.  결국 유스케이스 다이어그램은 프로젝트 수행시 가장 먼저 나오는 다이어그램이고 다른 다이어그램의 배경이 되는 중요한 다이어그램이다.  이제부터 유스케이스 다이어그램을 자세히 알아보도록 하겠다.
 
1. 표기(Notation)과 의미(Semantics)
(1) 유스케이스(Usecase)
그림 1. 유스케이스

유스케이스의 표기는 그림 1에서와 같이 타원으로 표시하고 이름을 속에 명시하게된다.
(2) 유스케이스의 의미.
유스케이스는 말 그대로 쓰임새를 나타낸다. 다시 말해 한 프로젝트의 결과물이 작동하여 사용되는 쓰임새를 분류하여 나타내는 것이다. 예를 들어 우리가 늘 상주하는 집을 들면 집이 사용되어지는 예를 들 수가 있다. 집은 식사를 위한 장소를 사용되어질 수 있고 아니면 휴식을 위한 장소 아니면 수면을 취하기 위한 장소.. 등등 여러가지 용도의 사용 예를 들 수 있다. 결국 이러한 여러 사용 예들이 집의 구조를 결정하는 사항이 될 것이다.
(3) 액터(Actor)

그림 2 - 액터

그림 3 - 스테레오 타입이 액터인 클래스
액터의 경우 그림 2에서 보는 바와 같이 스틱맨으로 표시하고 그 하단에 액터의 이름을 명시한다.  또한 그림 3와 같이 스테레오타입(Stereotype)을  'Actor' 로 가지는 클래스로 표기하기도 한다.
(4) 액터의 의미
액터는 구축해야할 시스템과 상호 교류하는 어떠한 사람이나 어떤 것이 될 수 있다. 예를 들어 입출금할 수 있는 ATM기계를 보면 입출금을 하는 행위자인 손님의 경우 하나의 액터가 될 수 있다. 그리고 ATM기계가 입출금의 처리를 위해 연결하는 은행의 주 전산망 또한 하나의 액터가 될 수 있다. 이렇듯이 구축하고자 하는 시스템의 쓰임새와 교류하는 외부적인 것들의 추상적인 역할을 액터라고 한다.
 
2. 액터들간의 관계(Relationship)
(1) 일반화(Generalization) 관계의 표기

그림 4 -액터와 액터 사이의 일반화 관계 
(2) 일반화 관계의 의미
일반화 관계는 객체지향의 상속의 의미와 유사하다. 일반화된 액터의 모든 특성을 특수한 액터가 모두 가지게 된다. 그림 4에서와 같이 고객 액터의 모든 특성을 상업고객이 모두 포함하게 된다.
 
3. 액터와 유스케이스, 유스케이스와 유스케이스 사이의 관계
유스케이스와 유스케이스사이의 관계를 말하기에 앞서 알아두어야 할 사항이 있다. 현재 UML의 표준화된 버전은1.1 이다. 하지만 현시점에도 계속 버전업을 위한 수정이 가해지고 있다. 결과적으로 현재 1.3 RTF라는 표준화되지 않은 버전 또한 나와 있다.  유스케이스와 유스케이스와의 관계에서 1.1버전과 1.3버전의 차이점이 존재함을 유념하기 바란다.  필자는 표준인 1.1 을 대상으로 설명을 하도록 하겠다.
(1) 통신(Communicates) 관계

그림 5 - 통신(Association) 관계 
(2) 통신 관계의 의미
통신관계의 의미는 이러한 관계로 묶인 두 개체가 상호 작용을 한다는 의미이다.  그림 5에서와 같이 현금자동출납기계의 시스템에서 그 사용자와 사용자확인의 유스케이스는 상호작용을 하게 된다. 이를 관계로 표시한 것이 통신 관계이다. 참고로 UML1.3 RTF의 경우 통신관계는 연관(Association) 관계로 대체되어 사용되게 된다.
(3) 확장(Extends) 관계

그림 6 - 확장(Extends) 관계
(4) 확장 관계의 의미
확장(Extends)관계는 유스케이스가 어떤한 조건이 만족할 경우 확장할 수 있는 확장시점(Extention Point)를 가지고 그 때 연관된 유스케이스를 포함하는 관계이다 예를 들면 그림 6에서와 같이 추가 요구시라는 확장시점에서 카탈로그요구의 유스케이스가 주문접수의 유스케이스에 포함되게 된다.
(5) 사용(Uses) 관계

그림 7 - 사용(Uses) 관계
(6) 사용 관계의 의미
사용관계는 특정한 유스케이스가 다른 유스케이스를 포함하고 있는 경우를 나타낸다. 그림 7에서는 고객확인의 유스케이스가 주문접수의 유스케이스와 주문조사의 유스케이스를 모두 포함하게 되는 경우이다. UML 1.3 RTF에서는 Uses의 관계가 include의 관계로 이름이 바뀌어서 사용되게 된다.
(7) 일반화(Generalization) 관계 

그림 8 - 일반화(Generalization) 관계
(8) 일반화 관계의 의미
일반화 관계는 액터 사이의 일반화 관계와 동일하게 객체지향의 상속의 개념과 유사하다. 
 
4. 액터와 유스케이스의 추출법.
실제로 시스템을 구축하기 위해 유스케이스 다이어그램을 그릴 때 액터와 유스케이스를 만들기가 막막할 것이다. 물론 정확한 액터와 유스케이스를 추출하기 위해서는 여러 번의 반복이 필요하지만 처음으로 추출할려는 사람은 다음과 같은 대충의 지표 등을 통해 추출해보는 것도 좋다.
(1) 액터의 추출법
  1. 시스템의 주기능을 사용하는 사람은 누구인가.
  2. 누가 시스템으로부터 업무 지원을 받는가?
  3. 누가 시스템을 운영, 유지 보수하는가?
  4. 시스템과 정보를 교환하는 외부 시스템은 무엇인가?
  5. 시스템이 내어놓은 결과물에 누가 관심을 가지는가?
(2) 유스케이스 추출법
  1. Actor가 요구하는 시스템의 주요 기능은 무엇인가?
  2. Actor가 시스템의 어떤 정보를 수정, 조회, 삭제, 저장하느가?
  3. 시스템이 Actor에게 주는 어떠한 Event가 있는가?,  Actor가 시스템에는 어떠한 Event가 있는가?
  4. 시스템의 입력과 출력으로 무엇이 필요한가? 그리고 입력과 출력이 어디에서 오고 어디에로 가는가?
  5. 시스템의 구현에서 가장 문제가 되는 점은 무엇인가?
 
5. 시나리오
유스케이스 다이어그램을 그리면서 빠뜨려서는 안될 내용이 시나리오이다. 유스케이스 다이어그램을 완성하였다면 유스케이스 다이어그램의 명세가 필요하게 된다. 즉 유스케이스 다이어그램이 무엇을 해야하고 어떻게 해야하는가에 같은 부연 설명이 필요한 것이다. 유스케이스는 순서에 의해 배열이 가능하고 이러한 순서를 일반적인 자연어 문장으로 표현하되 외부인이 보아도 알기쉬운 정도로 쉽게 기술하여야 한다.
마무리?
유스케이스 다이어그램은 다른 다이어그램을 그리기 위한 바탕이 되는 다이어그램이다. 즉 유스케이스 다이어그램이 잘못 되었다면 결과물은 잘못된 것일 수밖에 없다. 유스케이스 다이어그래이 잘 되었다면 이후 그려나갈 다른 다이어그램이 원래의 목적에 맞게 그릴 수 있는지 비교할 수 있는 좋은 바탕이 될 수 있다.
참고로 유스케이스 다이어그램을 잘 그리기 위해 다음의 단계로 넘어가는 것을 주저하지 말기 바란다. 프로젝트를 잘 수행하기 위해서는 여러 번의 반복적 개발을 통해 오류의 수정 과정이 필요하고 이에 유스케이스 다이어그램을 수정하는 일도 포함된다. 즉 어느 정도 유스케이스 다이어그램이 완성되면 다음의 다이어그램을 진행하길 바란다.

개발/소프트웨어공학 | Posted by 은우 아빠 2008. 10. 1. 16:03

UML의 구성


1. UML과 방법론의 차이
UML의 구성을 알아보기에 앞서 먼저 UML과 방법론의 차이를 알아야 한다. 필자는 UML을 공부하는 초기에 UML을 하나의 방법론으로 착각하는 오류를 하였다. 물론 똑똑한 독자는 이러한 오류를 범하지 않으리라 생각하지만 혹시나 하는 마음에 먼저 언급하려고 한다.
방법론이란 말그대로 어떠한 작업을 할 때 이러저러한 절차를 가지고 작업을 하면 된다라고 하는 것을 이론적으로 정립을 하여놓은 것이다. 소프트웨어공학에서 많은 방법론이 있어왔고 현재도 수많은 방법론이 존재한다. 사실 프로그램을 하는 모든 사람은 나름대로의 방법론을 가지고 있다. 그러한 나름의 방법론이 작업을 얼마만큼 효과적으로 만드는지에 따라 좋은 방법론인지 아닌지 결정 날 것이다.
그럼 UML은 무엇인가?  UML은 이러한 방법론을 적용할 때의 결과물을 나타내기 위한 도구이다.  예를 들면 모든 소프트웨어를 설계 할 때 어떠한 표준적인 규칙을 가지고 설계도를 그려야한다. 이때 설계의 표준이 되는 것이 UML이다.  건축도면에서 나오는 건물 내부의 여러가지 표준적인 표기라 보면 될 것이다.  즉 각자 다양한 방법론을 자기의 프로젝트에 적용하더라도 UML을 공통적으로 적용할 수 있다.
2. UML의 구성
이제 UML이 어떻게 구성되어있는지 알아보도록 하겠다.  전체 UML은 8가지 다이어그램으로 나타난다. 시스템의 정적인 면을 나타내는 클래스 다이어그램(Class Diagram)이 있고 동적인 면을 나타내는 콜레버레이션 다이어그램(Collaboration Diagram), 시퀸스 다이어그램(Sequence Diagram), 상태 다이어그램(Statechart Diagram), 액티비티 다이어그램(Activity Diagram), 디플로이먼트 다이어그램(Deployment Diagram), 컴포넌트 다이어그램(Component Diagram)으로 구성되어져 있다.
이외로 유스케이스 다이어그램(Usecase Diagram)이 존재한다. 유스케이스 다이어그램을 두 부류로 나누지 않은 이유는 다른 모든 다이어그램을 그리기 위해 기반이 되는 다이어그램이기 때문이다.이제 각 다이어그램이 시스템의 어떠한 면을 반영하는지 간단하게 알아보도록 하자.
(1) 유스케이스 다이어그램 (Usecase Diagram)
유스케이스 다이어그램은 유스케이스를 그려놓은 다이어그램이다. 여기서 유스케이스란 말 그대로 컴퓨터 시스템과 사용자가 상호작용을 하는 하나의 경우이다. 예를들어 보험처리 프로그램의 경우에 "고객이 보험증권에 sign한다.",  "보험 판매원이 판매통계량을 종합한다." 등이 use case가 된다. 이러한 유스케이스 다이어그램은 시스템 구축의 초기에 이 시스템이 어떠한 일을 하는지에 대한 부분을 사용자 입장에서 이해할 수 있을 정도로 기술을 하여야 한다. 이러한 유스케이스 다이어그램은 사용자와의 대화수단으로 그리고 앞으로 구축해 나갈 때의 밑바탕이 되는 것이다.

그림 1 - 유스케이스 다이어그램
(2) 클래스 다이어그램 (Class Diagram)
클래스 다이어그램의 경우 시스템 내부에 존재하는 클래스들을 선별하여 나타내고 각 클래스들의 속성(Attribute)과 행위(Behavior)를 기입한다. 여기서 클래스들 사이에 여러가지 관계(Relationship)를 가질수 있다. 예를 들어 연관관계(Association)은 클래스와 클래스가 어떠한 연관을 가지고 있음을 나타내고 여기서 세부적으로 복합연관(Composition)과 집합 연관관계 (Aggregation) 등으로 나뉘어 질 수 있다. 이외에 상속관계(Generalization), 의존관계(Dependency)가 나타날 수 있다. 클래스 다이어그램을 그리고자 할 때 항상 추상화 단계를 고려하여서 그리도록 하여야 할 것이다. 추상화의 단계가 높은 경우 대충의 속성과 행위를 기입하고 대충의 관계를 기입하여도 충분할 것이다. 이 단계에서 너무 상세한 내용을 찾고 기입하다 보면 클래스 다이어그램 내부에서 구현의 단계에서 이루어져야 할 일이 이루어지는 오류를 범하게 된다. 이러한 오류는 실제 구현 단계에서 커다란 위험의 요소를 내재하게 된다.

그림 2 - 클래스 다이어그램
(3) 시퀸스 다이어그램 (Sequence Diagram)
시퀸스 다이어그램은 콜레버레이션 다이어그램과 함께 시스템의 동적인 면을 나타내는 대표적인 다이어그램이다. 시스템이 실행시 생성되고 소멸되는 객체를 표기하고 객체들 사이에 주고 받는 메시지를 나타내게 된다. 콜레버레이션 다이어그램 또한 메시지의 흐름을 나타내지만 시퀸스 다이어그램 만의 특징이라면 횡축을 시간축으로 하여 시간의 흐름을 나타내어 메시지의 순서에 역점을 두고있다.

그림 3 - 시퀀스 다이어그램
(4) 콜레버레이션 다이어그램 (Collaboration Diagram)
콜레버레이션 다이어그램 또한 시퀸스 다이어그램과 함께 메시지의 흐름을 나타낸다. 하지만 콜레버레이션 다어그램은 객체와 객체들 사이의 관계 또한 표기하게 된다. 실제 UML에서 클래스의 인스턴스인 객체를 표기하는 다이어그램이 명시적으로 존재하지 않는다. 이러한 객체들 사이의 관계를 나타내기 위해 별도로 오브젝트 다이어그램(Object Diagram)을 사용하여도 되지만 오브젝트 다이어그램은 클래스 다이어그램과 크게 차이점이 없는 관계로 UML의 표준에는 포함되어있지 않다. 갑자기 이러한 오브젝트 다이어그램을 여기서 언급하는 이유는 객체들 사이의 관계를 표기하기 위해 클래스 다이어그램과 거의 동일한 오브젝트 다이어그램을 그리기 보다는 특별히 클래스 다이어그램과 차이점이 되는 부분을 여기 콜레버레이션 다이어그램에 기입하는 것이 좋을 것이다.

그림 4 - 콜레버레이션 다이어그램
(5) 상태 다이어그램 (Statechart Diagram)
상태 다이어그램은 한 객체의 상태 변화를 다이어그램으로 나타낸 것이다. 시스템의 실행시 객체의 상태는 메시지를 주고 받음으로써 또한 어떠한 이벤트를 받음으로써 많은 변화가 있을 수 있다.  실제 시스템에서 실행시 많은 객체가 생성되고 소멸된다. 이렇게 무수한 객체의 상태 전부를 모두 다이어그램으로 나타내는 것은 불가능하다.  결국 상태 다이어그램은 특별히 관심을 가져야 할 객체에 관하여 그리고 특정 조건에 만족하는 기간동안의 상태를 표시하여야 한다.

그림 5 - 상태 다이어그램
(6) 액티비티 다이어그램 (Activity Diagram)
액티비티 다이어그램은 플로우챠트가 UML에 접목이 되었다면 가장 이해가 빠를 것이다.  시스템 내부에 존재하는 여러가지 행위들 그리고 각 행위의 분기, 분기되는 조건 등을 모두 포함 하게 된다. 이러한 액티비티 다이어그램에서 기존 플로우 챠트와 다른 점은 어떠한 행위에 따라 객체의 상태를 표기할 수 있다는 것이다. 이러한 점을 제외하고 기존 플로우챠트와 표기법과 의미가 약간씩 달라질 뿐 크게 다르지 않다라고 보아도 좋다.

그림 6 - 액티비티 다이어그램
(7) 디플로이먼트 다이어그램 (Deployment Diagram) 과 컴포넌트 다이어그램 (Component Diagram)
이 두 다이어그램은 시스템의 물리적인 부분의 구성을 나타낸다. 디플로이먼트 다이어그램은 실제 하드웨어적인 배치와 연결상태를 나타낸다. 그리고 컴포넌트 다이어그램은 소프트웨어의 물리적 단위(Exe, dll 등 기타 library)의 구성과 연결상태를 나타내게 된다.

그림 7 - 디플로이먼트 다이어그램

그림 8 - 컴포넌트 다이어그램
3. 이외의 사항들
지금까지 UML의 다이어그램적인 구성에 대하여 알아보았다. 하지만 UML은 이러한 다이어그램적인 사항이 아닌 확장을 위한 여러가지 도구들을 준비되어있다. 예를들어 스테레오타입(Stereotype)이나 컨스트레인트(Constraint) 등의 의미적 변환을 위한 도구가 있다. 그리고 UML은 의미적인 무결성을 위해 메타모델을 위해 준비해 두었다. 이제 전체적인 UML의 구성이 어떻게 되어있는지 알수 있을 것이다.  다음 회부터 본격적으로 UML의 세부적 사항을 요목조목 알아보도록 하겠다.

이 글에 삽입된 다이어그램은 “Plastic Software”의 UML 모델링 툴인 “PLASTIC 2.0”을 이용하여 그렸다.

개발/소프트웨어공학 | Posted by 은우 아빠 2008. 10. 1. 15:56

UML 강좌


UML1) ?
객체지향 분석/설계 산물(artifacts)을 위한, 표준화된 notation
Not a method
Not a development process
UML은 모델링 언어의 통합을 위한 표준
UML은 s/w를 시각화, 명세화, 문서화하기 위한 언어
UML은 시스템의 여러 분야를 포함
데이터 모델링(Entity Relationship Diagram)
객체 모델링
Component 모델링
개발/자바 | Posted by 은우 아빠 2008. 10. 1. 10:04

JUnit 기본 사용법


JUnit은 자바 세계에서 가장 널리 사용되어지고 있는 단위 테스팅 도구이다. Eclipse를 비롯한 대부분은 IDE는 JUnit을 기본으로 지원하고 있다. 단위테스트에 국한되어 있어 모든 테스트를 소화하기엔 부족한 점이 있지만, 기능의 확장을 위해 이를 기반으로 한 Add-ons 이나 Extensions 들이 많이 나와있다. 현재까지 가장 많이 쓰여 왔던 JUnit 3.8 버전의 사용법을 간단히 정리해본다.

1. 기본 테스트 예제

import junit.framework.TestCase;

public class SimpleTest extends TestCase {
	private int x = 3;
	private int y = 2;
	
	public void testAddition() {
		int z = x + y;
		assertEquals(5, z);
	}
}
- junit.framework.TestCase 를 상속한 테스트용 클래스 생성.
- public void 타입으로 선언된 test* 로 시작되는 테스트 메소드 작성.
- assert 로 테스트 결과 검증.

2. setUp과 tearDown을 이용한 각 테스트 메소드 실행시마다 초기화 및 종료화 처리 예제

import junit.framework.TestCase;

public class SetupTest extends TestCase {
	private int x;
	private int y;
	
	protected void setUp() {
		x = 3;
		y = 2;
		System.out.println("setUp()");
	}
	
	public void testAddition() {
		int z = x + y;
		assertEquals(5, z);
	}
	
	public void testSubtraction() {
		int z = x - y;
		assertEquals(1, z);
	}
	
	protected void tearDown() {
		System.out.println("tearDown()");
	}
}
- 각 테스트 마다 매번 setUp() 과 tearDown() 실행.

3. TestSetup를 이용한 클래스내 모든 테스트 실행 전 초기화와 실행 후 종료화 처리 예제

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

public class TestSetupTest extends TestCase {
	private static int x;
	private static int y;

	public static Test suite() {
		TestSetup setup = new TestSetup(
				new TestSuite(TestSetupTest.class)) {
			protected void setUp() {
				x = 3;
				y = 2;
				System.out.println("setUp()");
			}
			
			protected void tearDown() {
				System.out.println("tearDown()");
			}
		};
		return setup;
	}

	public void testAddition() {
		int z = x + y;
		assertEquals(5, z);
	}

	public void testSubtraction() {
		int z = x - y;
		assertEquals(1, z);
	}
}
- 모든 테스트 실행 전과 실행 후 단 1회만 setUp()과 tearDown() 실행.

4. 예외 테스트 예제

import junit.framework.TestCase;

public class ExceptionTest extends TestCase {	
	public void testDivisionByZero() {
		try {
			int n = 2 / 0;
			fail("Divided by Zero!"); // 실패
		}
		catch (ArithmeticException ae) {
			assertNotNull(ae.getMessage()); // 성공
		}
	}
}

5. TestSuite를 이용한 모든 테스트 실행 예제

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

public class AllTests {
	public static Test suite() {
		TestSuite suite = new TestSuite("All JUnit Tests");
		suite.addTestSuite(ExceptionTest.class);
		suite.addTestSuite(SetupTest.class);
		suite.addTestSuite(SimpleTest.class);
		suite.addTest(TestSetupTest.suite());
		return suite;
	}

	public static void main(String[] args) {
		junit.textui.TestRunner.run(suite());
	}
}





 protected String strCut(String szText, int nLength)
 { // 문자열 자르기
  String r_val = szText;
  int oF = 0, oL = 0, rF = 0, rL = 0;
  int nLengthPrev = 0;
  try
  {
   byte[] bytes = r_val.getBytes("UTF-8"); // 바이트로 보관
   // x부터 y길이만큼 잘라낸다. 한글안깨지게.
   int j = 0;
   if (nLengthPrev > 0)
    while (j < bytes.length)
    {
     if ((bytes[j] & 0x80) != 0)
     {
      oF += 2;
      rF += 3;
      if (oF + 2 > nLengthPrev)
      {
       break;
      }
      j += 3;
     }
     else
     {
      if (oF + 1 > nLengthPrev)
      {
       break;
      }
      ++oF;
      ++rF;
      ++j;
     }
    }
   j = rF;
   while (j < bytes.length)
   {
    if ((bytes[j] & 0x80) != 0)
    {
     if (oL + 2 > nLength)
     {
      break;
     }
     oL += 2;
     rL += 3;
     j += 3;
    }
    else
    {
     if (oL + 1 > nLength)
     {
      break;
     }
     ++oL;
     ++rL;
     ++j;
    }
   }
   r_val = new String(bytes, rF, rL, "UTF-8"); // charset 옵션
  }
  catch (UnsupportedEncodingException e)
  {
   e.printStackTrace();
  }
  return r_val;
 }
개발/WEB2.0 | Posted by 은우 아빠 2008. 9. 26. 18:07

RSS 문서 제작을 위한 RSS 규약의 이해 (RSS 2.0)












RSS 항목 

 항목의 의미  사용법 

<?xml version="1.0" encoding="euc-kr" ?> 

XML 파싱을 위해 필요한 정보 선언 

<rss version="2.0"> 

RSS 버전 선언 

<channel> 

RSS 정보가 시작됨을 의미 

<title>오마이뉴스</title> 

RSS 제공 사이트의 타이틀을 기록 

<link>http://www.ohmynews.com/</link> 

RSS 제공 사이트의 URL  기록 

<description>뉴스게릴라들의뉴스-오마이뉴스</description> 

RSS 제공 사이트의 간단한 설명을 기록 

<language>ko</language> 

RSS 문서에서 사용되는 국가 언어 선언 

<copyright>Copyright (c) OhmyNews.com All rights reserved</copyright> 

RSS 문서 저작권 선언 

<lastBuildDate>Fri, 8 Apr 2005 14:30:20 +0900</lastBuildDate> 

RSS 문서가 최종 작성된 시간 기록 

<item> 

 기록시작. 

<title>- <![CDATA[ '거창 민간인 학살사건' 위령제 11   ]]> </title> 

글의 제목 

<link>http://www.ohmynews.

com/ArticleView/article_view.asp

?no=219789&rel_no=1</link> 

글의 전문(全文) 확인할  있는 웹주소 

<description>- <![CDATA[ 한국전쟁 전후 거창지역 민간인 희생자  합동  ]]> </description> 

글내용 일부 또는 전체를 기록 

<category>사회</category> 

글이 포함되는 카테고리 

<author>(성효 기자)</author> 

글의 저작자를 기록 

<pubDate>Fri, 8 Apr 2005 13:57:20 +0900</pubDate> 

글이 작성된 시간을 기록 

</item>  

</item> 태그를 닫음으로써 글에 대한 정보가 완료됨을 선언
( 개수만큼 <item>…</item> 태그 반복) 

</channel> 

열어놓은 채널을 닫음. 

</rss> 

열어놓은 rss 태그를 닫음. RSS 문서의 .