유튜브에서 그냥 킹오브 98이나 보려고 들어갔다가 다음과 같은 영상이 메인에 보였다. 꼴에 프랑스어를 조금 배우고 프로그래밍도 조금 배웠다고 유튜브 알고리즘이 띄워주나 보다. 보다보니 뭔가 IDE와 빌드툴의 도움만 받으면서 근본도 모르고 개발을 한 것 같아 영상의 내용을 글로 옮겨본다. 모하메드 교수님이 불어로 쏼라쏼라 하지만 코드는 만국 공통이니 못 알아 들을 것도 없었다. 시작해 보자!
1. mkdir example && cd example
2. mkdir -p src/main/java
3. mkdir -p src/test/java
4. mkdir -p src/main/resources
5. mkdir -p target/classes
6. mkdir lib
mkdir의 -p
옵션은 바로 필요한 디렉터리를 한 번에 만들겠다는 뜻 이다.
main
폴더를 만든다.test
폴더를 만든다.resources
폴더를 만든다..class
파일들을 저장할 곳을 만든다..jar
파일들을 저장하는 곳을 만든다.tree
명령어를 사용해서 다음과 같은 구조가 보이면 된다.
.
├── lib
├── src
│ ├── main
│ │ ├── java
│ │ └── resources
│ └── test
│ └── java
└── target
└── classes
💡 맥 OS에는 tree 명령어가 없다.
brew install tree
1. cd src/main/java
2. mkdir -p com/example/app && cd com/example/app
3. vi App.java
App.java
라는 이름의 파일로 vim 에디터를 연다.그리고 다음과 같이 아주 간단히 main 메소드를 포함하는 자바 코드를 작성해본다. 이후에 다른 클래스를 import 해볼 것이니 걱정하지 말자!
package com.example.app;
public class App {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
프로젝트의 루트 경로로 돌아간 후 아래의 명령어를 실핸한다.
javac src/main/java/com/example/app/App.java -d target/classes
App.java
파일을 컴파일하고 결과를 target/classes
디렉토리에 넣는다는 뜻이다.
tree 명령어를 실행해보면 다음과 같다.
.
├── lib
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ └── App.java
│ │ └── resources
│ └── test
│ └── java
└── target
└── classes
└── com
└── example
└── app
└── App.class
자, 이제 실행해보자!
java -cp target/classes com.example.app.App
-cp
는 클래스 패스를 설정하는 옵션이다. App.class
파일을 실행한다.
결과는 예상대로 다음과 같다.
Hello World
클래스 패스를 매번 지정해 주어야하는게 조금 귀찮다. java com.example.app.App
을 실행하면 다음과 같이 클래스를 찾을 수 없다고 오류가 나타난다.
Error: Could not find or load main class com.example.app.App
Caused by: java.lang.ClassNotFoundException: com.example.app.App
클래스 패스 설정 없이 바로 자바 프로그램을 실행하고 한다면 다음과 같이 환경 변수에 클래스 패스를 지정해주어야 한다.
export CLASSPATH="/[YOUR_PATH_HERE]/example/target/classes:$CLASSPATH"
그리고 나서 java com.example.app.App
을 실행하면 "Hello World"가 똑같이 나타날 것이다.
1. mkdir src/main/java/com/example/app/service && cd src/main/java/com/example/app/service
2. vi Service.java
service
패키지를 추가하고 해당 경로로 이동한다.Service.java
이름의 파일을 에디터로 연다. 아래의 내용을 작성한다.package com.example.app.service;
public class Service {
public double compute(double a, double b) {
return a + b;
}
}
프로젝트의 루트로 경로를 다시 이동시키고 아래의 명령어를 실행시킨다.
javac -d ./target/classes ./src/main/java/com/example/app/service/Service.java
tree 명령어를 실행해보면 다음과 같다.
.
├── lib
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ ├── App.java
│ │ │ └── service
│ │ │ └── Service.java
│ │ └── resources
│ └── test
│ └── java
└── target
└── classes
└── com
└── example
└── app
├── App.class
└── service
└── Service.class
Service.class
파일이 생긴 것을 확인할 수 있다.
App.java
파일을 다음과 같이 수정한다. 코드 설명은 따로 하지 않아도 알 것이다.
package com.example.app;
import com.example.app.service.Service;
public class App {
public static void main(String[] args) {
if(args.length != 2) {
System.out.println("두 개의 인수를 주세요!");
System.exit(0);
}
Service service = new Service();
double a = Double.parseDouble(args[0]);
double b = Double.parseDouble(args[1]);
double result = service.compute(a, b);
System.out.println(String.format("%s 더하기 %s 는 %s 이다.", a, b, result));
}
}
다시 App.java
파일을 컴파일 해본다.
javac -d ./target/classes ./src/main/java/com/example/app/App.java
앱을 실행해본다.
java com.example.app.App
결과는 다음과 같다.
두 개의 인수를 주세요!
두 개의 인수를 주고 다시 실행해본다.
java com.example.app.App 5 7
결과는 다음과 같다.
5.0 더하기 10.0 는 15.0 이다.
필요한 import 하고 컴파일하고 실행까지 해보았다!
테스트 코드 작성 및 실행에 필요한 jar 파일들을 다운받는다.
다운로드 받은 후 lib
경로에 넣어준다.
src/test/java
경로에 똑같은 com/example/app/service
패키지를 만들고 ServiceTest.java
파일을 생성하여 테스트할 코드를 작성한다. 일부러 실패하는 테스트로 만들었다.
package com.example.app.service;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ServiceTest {
@Test
public void testCompute() {
Service service = new Service();
double a = 12;
double b = 8;
double expected = 100;
double result = service.compute(a, b);
assertEquals(result, expected, 0.001);
}
}
jar 파일과 직접 컴파일한 클래스를 불러올 수 있도록 클래스패스를 설정하여 ServiceTest.java
를 컴파일 한다.
javac -d ./target/classes -cp ./lib/junit-4.13.jar:./lib/hamcrest-core-1.3.jar:./target/classes ./src/test/java/com/example/app/service/ServiceTest.java
tree 명령어를 실행해보면 다음과 같다.
.
├── lib
│ └── junit-4.13.jar
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── app
│ │ │ ├── App.java
│ │ │ └── service
│ │ │ └── Service.java
│ │ └── resources
│ └── test
│ └── java
│ └── com
│ └── example
│ └── app
│ └── service
│ └── ServiceTest.java
└── target
└── classes
└── com
└── example
└── app
├── App.class
└── service
├── Service.class
└── ServiceTest.class
JUnit 4의 테스트를 실행하기 위해 JUnitCore 가 필요하다. 해당 문서에 커맨드 라인에서의 실행법이 나와있다.
To run tests from the command line, run java org.junit.runner.JUnitCore TestClass1 TestClass2
다시 한 번 클래스 패스를 설정해 필요한 클래스들을 불러오고 JUnitCore
로 테스트를 실행해 본다.
java -cp "./target/classes/:./lib/junit-4.13.jar:./lib/hamcrest-core-1.3.jar:" org.junit.runner.JUnitCore com.example.app.service.ServiceTest
결과는 다음과 같다.
JUnit version 4.13
.E
Time: 0.006
There was 1 failure:
1) testCompute(com.example.app.service.ServiceTest)
java.lang.AssertionError: expected:<20.0> but was:<100.0>
at org.junit.Assert.fail(Assert.java:89)
at org.junit.Assert.failNotEquals(Assert.java:835)
at org.junit.Assert.assertEquals(Assert.java:555)
at org.junit.Assert.assertEquals(Assert.java:685)
at com.example.app.service.ServiceTest.testCompute(ServiceTest.java:14)
FAILURES!!!
Tests run: 1, Failures: 1
잘 동작한다 😙.
jar 파일로 만들어 앱을 실행시켜 보자. 경로를 target/classes
를 이동시켜 target
경로에 app.jar
파일을 만든다.
jar cfv ../app.jar .
옵션의 의미는 다음과 같다.
c
: 자바 아카이브 파일을 생성한다.f
: 파일 이름을 정한다.v
: 콘솔에 진행상황을 출력한다.added manifest
adding: com/(in = 0) (out= 0)(stored 0%)
adding: com/example/(in = 0) (out= 0)(stored 0%)
adding: com/example/app/(in = 0) (out= 0)(stored 0%)
adding: com/example/app/App.class(in = 925) (out= 605)(deflated 34%)
adding: com/example/app/service/(in = 0) (out= 0)(stored 0%)
adding: com/example/app/service/Service.class(in = 272) (out= 210)(deflated 22%)
adding: com/example/app/service/ServiceTest.class(in = 559) (out= 393)(deflated 29%)
다음과 같은 정보가 나오며 app.jar
이 생성되었다.
target
경로에 jar 파일을 생성했으므로 해당 경로로 이동하고 다음의 명령어를 입력해 앱을 실행해 본다.
java -cp app.jar com.example.app.App 10 2
결과는 다음과 같다.
10.0 더하기 2.0 는 12.0 이다.
resources
폴더에 MANIFEST.TXT
파일을 만들고 다음 내용을 추가한다.
Main-Class: com.example.app.App
💡 줄바꿈을 통해 마지막 빈 줄을 만드는 것이 매우 중요하다!!!!
target/classes
경로로 이동한 후 Manifest 파일을 app.jar
생성 시 추가시켜준다 (Manifest 파일 경로를 명시해주지 않으면 디폴트로 알아서 하나 만들어 준다).
jar cfvm ../app.jar ../../src/main/resources/MANIFEST.TXT .
target
으로 이동해 앱을 실행시켜 본다.
java -jar app.jar 20 30
결과는 다음과 같다.
20.0 더하기 30.0은 50.0 이다.
한 번 알아본 것으로 족하고 IDE와 빌드툴에 의존해야 겠다 🤪.