[JUnit4] @FixMethodOrder를 사용한 테스트 메소드 실행 순서 결정하기

Published on: 2013.11.29 18:53 by krespo

JUnit 4.11버전 부터 @FixMethodOrder 라는 어노테이션이 생겼습니다. 

이 어노테이션은 테스트 메소드의 실행 순서의 기준을 잡을수 있도록 해줍니다.


@FixMethodOrder는 3가지 정렬 옵션을 가지고 있습니다.

 속성

설명 

 MethodSorters.DEFAULT

HashCode를 기반으로 순서가 결정되기 때문에 사용자가 예측하기 힘듭니다.

 MethodSorters.JVM

JVM에서 리턴되는 순으로 실행됩니다. 때에 따라서 실행시 변경됩니다.

 MethodSorters.NAME_ASCENDING

메소드 명을 오름차순으로 정렬한 순서대로 실행됩니다.


위의 옵션은 테스트케이스에서 아래와 같이 사용하시면 됩니다.


@FixMethodOrder(MethodSorters.DEFAULT)
public class JunitOrderTest {
	@Test
	public void test1() {
		System.out.println("Test1 Run!!");
	}
	@Test
	public void test2() {
		System.out.println("Test2 Run!!");
	}
}

Name
Password
Homepage
Secret

[Maven] properties내용을 command창에서 바로 입력하기

Published on: 2013.11.14 14:14 by krespo
Maven에서는 .properties파일 또는 pom.xml에 직접 <properties>를 통하여 DB의 접속정보라던지, 특정 dependency의 버전이라던지 하는 설정정보를 저장하여 관리할수 있다.(properties에 관한 자세한 내용은 여기에서) 이렇게 저장된 데이터들 중 pom.xml이나 properties파일에 직접 저장하기 껄끄러운데이터들이 있을 수 있다. 예를 들어 telnet이나 ftp에 로그인하기 위한 아이디와 패스워드 정보들은 pom.xml이나 .properties에 텍스트형태로 저장하게 되면 다른사람에게 그대로 노출이되어 보안에 취약하게 된다. 이런 껄끄러운 데이터들은 파일에 직접 저장하는 것이 아니라 Maven의 goal을 실행할때 파라미터로 전달하는 방법을 사용하면 된다. 아래의 설정은 Maven의 ant plugin으로 FTP를 사용하여 파일을 업로드하는 설정이다. 구체적으로 설명하지 않았지만 중요하게 봐야할 점은 FTP업로드시 userid와 password를 properties를 사용하게끔 설정했다는 것이다.
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>ftp</id>
      <phase>install</phase>
      <configuration>
        <tasks>
          <echo>SendFTP</echo>
          <ftp action="send" server="SERVERIP"
              remotedir="/a/b" userid="${ftp.userid}"
              password="${ftp.password}" depends="no"
              verbose="yes" binary="yes">
              <fileset dir="modules/my-module/target">
                <include name="my-static-file.zip" />
              </fileset>
            </ftp>
        </tasks>
      </configuration>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
  <dependencies>
    <dependency>
      <groupId>ant</groupId>
      <artifactId>ant-commons-net</artifactId>
      <version>1.6.5</version>
    </dependency>
    <dependency>
      <groupId>commons-net</groupId>
      <artifactId>commons-net</artifactId>
      <version>1.4.1</version>
    </dependency>
  </dependencies>
</plugin>
그리고 package goal을 실행할때 다음과 같이 입력한다.
$mvn package -Dftp.userid=krespo -Dftp.password=myftppassword
위에서 보듯이 ${ftp.userid}에는 krespo가 ${ftp.password}에는 myftppassword가 들어가는것을 확인해 보지 않고도 알수가 있다. 이렇듯 파라미터로 정보를 넘기려면
-D{key}={value}
형태로만 넣으면 어떠한 값이라도 동적으로 전달할 수 있게 된다.
Name
Password
Homepage
Secret

[Spring Framework] @RequestParam을 사용하여 List형 데이터 받을때 주의점

Published on: 2013.11.14 14:11 by krespo
html페이지로부터 전달되는 파라미터를 받아올때 @RequestParam 어노테이션을 사용해서 httpServletRequest 를 사용하지 않고도 데이터를 전달 받을 수 있다. 만약 페이지에서 name 속성을 동일하게 주어지면 @RequestParam을 이용해서 List형태로 받는것도 가능하다.
<form action="/submit" method="get">
	name=value1 <input type="text" name="value1" />
	name=value1 <input type="text" name="value1" />
	<input type="submit" value="submit" />
</form>
이렇게 textbox를 동일한 이름으로 submit을 하게 되면 파라미터는
value1=1111&value1=2222
처럼 동일한 파라미터 명을 가지게 되고 이 값을 스프링의 Controller에서 List형태로 받으려면
@RequestMapping("/submit")
public String submit(@RequestParam(value="value1", required=true) List<String> values) {
	System.out.println(values.size());  //2가 나오는것을 볼수 있다.
	return null;
}
처럼 사용할수 있다. 그런데 @RequestParam은 ,(comma)형태로 데이터를 보내게되도 ,(comma)를 구분자로하여 데이터를 쪼개서 List형태로 데이터를 변환한다.
//전달된 파라미터가 value1=111,222,333,444 형태라면
@RequestMapping("/submit")
public String submit(@RequestParam(value="value1", required=true) List<String> values) {
	for(String value : values) {
		System.out.println(value);    
	}
	//출력결과는 
	//111
	//222
	//333
	//444
	return null;
}
만약 html 뷰 페이지에서 다음과 같이 추가 버튼을 눌러 동적으로 입력 폼을 추가 하게되게끔 개발을 했다고 하면
<form action="/submit" method="get">
	name=value1 <input type="text" name="value1"/><button type="button" onclick="textbox추가 로직">추가</button>
	<input type="submit" value="submit" />
</form>
Controller에서는 몇개의 textbox가 추가가 될지 모르니 위와같이 @RequestParam을 이용해서 List형태로 받게 될것이다. 이때 textbox가 1개이고(추가버튼을 누르지 않고) 입력된 데이터가 ,(comma)로 구분되는 문자가 들어오게 된다면 우리는 의도했던것과는 다르게 사이즈가 1개이상인(콤마갯수 + 1개) List를 돌려받게 될것이다. 위와같은 문제가 발생될 소지가 있다면 어쩔수 없이 httpServletRequest의 getParameterValues 메소드를 사용하여 직접 받을 수 밖에 없으니 comma에 주의해서 @RequestParam 어노테이션을 사용하자.
Name
Password
Homepage
Secret

[Maven] Dependency Scope의 종류

Published on: 2013.11.14 14:10 by krespo
maven은 dependency 엘리먼트 하위의 scope 엘리먼트를 통해 포함하려는 라이브러리의 범위를 지정할 수 있다. Maven 3에서는 다음의 여섯가지 옵션을 지원하고 있다.
  • compile : 기본 scope이다. 만약 dependency에 아무것도 입력하지 않았다면 기본적으로 입력되는 scope이다. 이 옵션은 프로젝트의 모든 classpath에 추가된다(테스트 중이건 런타임 중이건 상관없이).
  • provided : 이 옵션은 compile과 매우 비슷하지만, 실행시 의존관계를 제공하는 JDK나 Web Container(tomcat 같은)에 대해서 적용된다.  예를 들어 Java Enterprise Edition Web application을 개발할때 Servlet API나 Java EE API들은 "provided" scope로 지정해야한다. 왜냐하면 Servlet API같은 경우는 Servlet Container 자체에서 지원해 주기 때문에(Tomcat 같은 경우는 ${tomcat home directory}/lib 디렉토리에 있는 Servlet 라이브러리를 사용) 컴파일시 또는 테스트시에는 필요하지만 실행시에는 필요하지 않기 때문이다.
  • runtime : 컴파일 시에는 필요하지 않지만 실행시에 사용되는 경우 사용한다. 이 옵션은 런타임, 테스트 시 classpath에 추가 되지만, 컴파일시에는 추가 되지 않는다.
  • test : 일반적인 경우에는 필요하지 않고 테스트시에만 필요한 경우 사용한다.
  • system : 해당 jar를 포함해야 한다고 명시적으로 입력 하는 것을 제외하고는 provided와 유사하다. 선언된 artifact들은 항상 사용가능하지만 Maven의 central repository에서 찾아서 가져오는 것은 아니다.
  • import : Maven 2.0.9 이상의 버전에서 지원하는 scope로서, 이 scope는 <dependencyManagement> 섹션에서 pom의 의존관계에 대해 사용된다. 지정된 pom이 해당 pom의 <dependencyManagement> 영역에 있는 의존관계로 대체됨을 뜻한다.
자세한 예제는 메이븐 공식 홈페이지 에서 확인할 수 있다.
Name
Password
Homepage
Secret

[Maven] package org.junit does not exists 에러 발생시

Published on: 2013.11.14 14:09 by krespo
오늘 우연히 Maven을 통해 packaging을 진행을 하다가 이런 에러를 발생시키면서 packaging이 진행되지 않았다.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.1:compile (default-compile) on project ${프로젝트명}: Compilation failure: Compilation failure:
[ERROR] ${에러 소스파일 경로}\${파일명}.java:[10,38] package org.junit.runners.Parameterized does not exist
[ERROR] ${에러 소스파일 경로}\${파일명}.java:[10,38] package org.junit.runners.Parameterized does not exist
[ERROR]
[ERROR] ${에러 소스파일 경로}\${파일명}.java:[10,38] package org.junit.runners.Parameterized does not exist
[ERROR]
[ERROR] ${에러 소스파일 경로}\${파일명}.java:[10,38] package org.junit.runners.Parameterized does not exist
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <goals> -rf :Infinite
에러내용을 읽어보니 org.junit.runers.Parameterized라는 패키지가 존재하지 않는다는 문제였다. 아마  검색을 통하여 이 포스트를 찾았다면 에러가 발생된 패키지 명은 달라도 모두 junit에서 발생한 문제일 것이다. 이문제는 컴파일 단계에서 junit 라이브러리가 포함이 되지 않아 발생하는 문제로 Maven의 버그가 아니라 pom파일의 dependency 설정때문에 발생한다.
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.8.1</version>
	<scope>test</scope>
</dependency>
위와같이 pom파일의 dependency 설정을통해 junit 라이브러리를 추가하게 되는데 이때 해당라이브러리의 사용범위를 지정할수있도록 Maven은 scope라는 엘리먼트를 지원해 주고 있다. 이때 scope를 test로 선언하게 되면 해당라이브러리는 테스트 중에만 사용을 하고 실제 packaging 중에는 포함이 되지 않는다. 이렇게 사용범위를 지정함으로서 불필요한 라이브러리 포함을 줄여 어플리케이션의 사이즈를 줄일수 있도록 만들게 되었다. 따라서 위와 같은 빌드 실패는 어플리케이션이 빌드되고 배포 되어질때 junit 라이브러리는 scope 설정때문에 패키징에서 제외되었음으로 org.junit.runers.Parameterized 패키지가 존재하지 않아 발생되는 문제이다. 필자의 경우에는 실제 org.junit.runers.Parameterized 패키지를 사용한 것이 아니라 mybatis의 @Param 어노테이션을 사용하려고 이클립스에서 지원하는 code assist 기능을 사용하여 입력하였고 그때 잘못 입력하여 java파일 상단에 import org.junit.runners.Parameterized.Parameters; 가 포함되었기 때문에 위와 같은 문제가 발생했다. 만약 각자의 코트에서 junit class를 런타임시에도 필요하다면(그럴일은 거의 없겠지만) scope 엘리먼트를 제거하면 되고, 그렇지 않으면 불필요한 import 문을 제거해 주면 깔끔하게 해결된다. 다른 dependency scope를 확인하고 싶다면 여기를 통해 확인하자.
Name
Password
Homepage
Secret