[Java] IDE 없이 개발하기

이충희·2021년 10월 16일
3

Java

목록 보기
3/3
post-thumbnail

발단

유튜브에서 그냥 킹오브 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 옵션은 바로 필요한 디렉터리를 한 번에 만들겠다는 뜻 이다.

  1. 프로젝트 폴더를 만들고 안으로 이동한다.
  2. 소스 코드를 작성하는 main 폴더를 만든다.
  3. 테스트 코드를 작성하는 test 폴더를 만든다.
  4. 설정 파일, 리소스 파일들을 담아두는 resources 폴더를 만든다.
  5. 컴파일 이후 .class 파일들을 저장할 곳을 만든다.
  6. 서드파티 라이브러리 .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
  1. 소스 코드 작성을 위해 java 폴더로 이동한다.
  2. 패키지를 만들고 경로를 이동한다.
  3. 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"가 똑같이 나타날 것이다.

import 할 클래스 작성

1. mkdir src/main/java/com/example/app/service && cd src/main/java/com/example/app/service
2. vi Service.java
  1. service 패키지를 추가하고 해당 경로로 이동한다.
  2. Service.java 이름의 파일을 에디터로 연다. 아래의 내용을 작성한다.
package com.example.app.service;

public class Service {
    public double compute(double a, double b) {
        return a + b;
    }
}

Service 컴파일

프로젝트의 루트로 경로를 다시 이동시키고 아래의 명령어를 실행시킨다.

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에 Service 임포트 시키기

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

App 실행하기

앱을 실행해본다.

java com.example.app.App

결과는 다음과 같다.

두 개의 인수를 주세요!

두 개의 인수를 주고 다시 실행해본다.

java com.example.app.App 5 7

결과는 다음과 같다.

5.0 더하기 10.0 는 15.0 이다.

필요한 import 하고 컴파일하고 실행까지 해보았다!

필요한 jar 파일 다운 받기

테스트 코드 작성 및 실행에 필요한 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 파일 만들기

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 이 생성되었다.

jar 파일 실행하기

target 경로에 jar 파일을 생성했으므로 해당 경로로 이동하고 다음의 명령어를 입력해 앱을 실행해 본다.

java -cp app.jar com.example.app.App 10 2

결과는 다음과 같다.

10.0 더하기 2.0 는 12.0 이다.

Manifest 추가 후 실행

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와 빌드툴에 의존해야 겠다 🤪.

참고 자료

profile
팔로우 기능 생기면 팔로우 당하고 싶다

0개의 댓글