'분류 전체보기'에 해당되는 글 418건
- 2008.10.04 FileZilla[파일질라], FileZillaServer[파일질라서버]
- 2008.10.02 TortoiseSVN 설치 및 사용방법
- 2008.10.01 엑셀함수활용콘사이스145.rar
- 2008.10.01 JUnit 을 이용한 단위 테스트
- 2008.10.01 클래스 다이어그램 3
- 2008.10.01 유스케이스(Usecase) 다이어그램 1
- 2008.10.01 UML의 구성
- 2008.10.01 UML 강좌
- 2008.10.01 JUnit 기본 사용법
- 2008.09.30 [Doc] MyEclipse 를 사용한 Struts + Spring + Hibernate 통합에 관련 문서
엑셀함수활용콘사이스145.rar
내용을 보시려면 비밀번호를 입력하세요.
유난히도 "버그"를 많이 발생시키는 프로그래밍 패턴때문에, 난 "버그양성소" 역할을 해왔었다. 그동안은 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



클래스의 의미는 일반적으로 객체지향 언어에서 사용하는 클래스의 의미와 유사하다. 클래스라는 것은 시스템에서 동작하게 되는 하나의 개념의 추상화 도구로써 사용되며 추상화의 단계에 따라 클래스의 의미가 약간씩 차이가 생긴다. 만약 설계 당시에 추상화가 아주 높은 단계에서 이러한 클래스는 시스템에서 사용되는 하나의 역할로서의 의미를 가진다. 하지만 구현단계와 같은 추상화 단계가 아주 낮은 상태에서는 실제 객체를 생성하기 위한 클래스의의미를 가지게 된다. 이러한 단계의 구별은 사용자의 의도에 따라 적당히 사용하면 될 것이다.

상속의 의미는 일반 언어에서의 상속의 의미와 유사하게 상위클래스의 모든 특징과 행위를 하위의 클래스가 모두 이어받게 된다. 즉 다양한 클래스들의 나열에서 동일한 행위나 특징을 가진 여러 클래스들이 존재할 때 공통되는 부분을 상위 클래스로 만들 수 있다.
4.클래스와 클래스의 연관관계(Association Relationship)




의존관계의 의미는 한 클래스의 변화가 다른 클래스에 영향을 미칠 때 사용한다. 이러한 의존의 관계는 여러가지 관계에서 나타날 수 있다. 의존관계의 종류에 관하여서는 다음 호에 자세히 다루도록 할 것이다.







유스케이스의 표기는 그림 1에서와 같이 타원으로 표시하고 이름을 속에 명시하게된다.

그림 2 - 액터

그림 3 - 스테레오 타입이 액터인 클래스

그림 4 -액터와 액터 사이의 일반화 관계

그림 5 - 통신(Association) 관계

그림 6 - 확장(Extends) 관계

그림 7 - 사용(Uses) 관계

그림 8 - 일반화(Generalization) 관계
- 시스템의 주기능을 사용하는 사람은 누구인가.
- 누가 시스템으로부터 업무 지원을 받는가?
- 누가 시스템을 운영, 유지 보수하는가?
- 시스템과 정보를 교환하는 외부 시스템은 무엇인가?
- 시스템이 내어놓은 결과물에 누가 관심을 가지는가?
- Actor가 요구하는 시스템의 주요 기능은 무엇인가?
- Actor가 시스템의 어떤 정보를 수정, 조회, 삭제, 저장하느가?
- 시스템이 Actor에게 주는 어떠한 Event가 있는가?, Actor가 시스템에는 어떠한 Event가 있는가?
- 시스템의 입력과 출력으로 무엇이 필요한가? 그리고 입력과 출력이 어디에서 오고 어디에로 가는가?
- 시스템의 구현에서 가장 문제가 되는 점은 무엇인가?
참고로 유스케이스 다이어그램을 잘 그리기 위해 다음의 단계로 넘어가는 것을 주저하지 말기 바란다. 프로젝트를 잘 수행하기 위해서는 여러 번의 반복적 개발을 통해 오류의 수정 과정이 필요하고 이에 유스케이스 다이어그램을 수정하는 일도 포함된다. 즉 어느 정도 유스케이스 다이어그램이 완성되면 다음의 다이어그램을 진행하길 바란다.

그림 1 - 유스케이스 다이어그램

그림 2 - 클래스 다이어그램

그림 3 - 시퀀스 다이어그램

그림 4 - 콜레버레이션 다이어그램

그림 5 - 상태 다이어그램

그림 6 - 액티비티 다이어그램

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

그림 8 - 컴포넌트 다이어그램
이 글에 삽입된 다이어그램은 “Plastic Software”의 UML 모델링 툴인 “PLASTIC 2.0”을 이용하여 그렸다.
객체지향 분석/설계 산물(artifacts)을 위한, 표준화된 notation
Not a method
Not a development process
UML은 모델링 언어의 통합을 위한 표준
UML은 s/w를 시각화, 명세화, 문서화하기 위한 언어
UML은 시스템의 여러 분야를 포함
데이터 모델링(Entity Relationship Diagram)
객체 모델링
Component 모델링
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); } } |
- 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()"); } } |
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); } } |
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()); } } |
[Doc] MyEclipse 를 사용한 Struts + Spring + Hibernate 통합에 관련 문서
