소스 코드를 기록하는 남자

Java Test Case @Before 어노테이션 실행이 안될때

카테고리 없음

본 포스팅은 필자가 한참 헤매서 작성하며, 혹여라도 길 잃은 영혼이 이 포스팅을 보고 해결되었으면 좋겠습니다.

 

저는 Intellij IDE 를 사용하며, 스프링 레거시 프로젝트를 진행하면서 공부하던 와중에 테스트 케이스를 작성 중에 @Before가 동작하지 않는 문제점입니다.

 

@Before 어노테이션이 동작하기 위해서는 기본적으로 필요한 @Test 어노테이션은 

1.  import org.junit.Test;

 

 

자동으로 import된 @Test 어노테이션은 ?

2. import org.junit.jupiter.api.Test;

 

따라서 Test import 문을 1번으로 변경해주시면 @Before가 잘 동작할 것입니다.

 

백준 6087번 : 레이저 통신 [Java]

Algorithm/백준

 

www.acmicpc.net/problem/6087

 

6087번: 레이저 통신

크기가 1×1인 정사각형으로 나누어진 W×H 크기의 지도가 있다. 지도의 각 칸은 빈 칸이거나 벽이며, 두 칸은 'C'로 표시되어 있는 칸이다. 'C'로 표시되어 있는 두 칸을 레이저로 통신하기 위해서

www.acmicpc.net

전형적인 백트래킹 문제다. 

 

문제의 요점은 탐색 + 백트래킹 장치를 거는 것이다.

 

여기서 백트래킹 장치라는 것은 레이저를 회전시키는 최소 횟수를 구하는 것이니, 회전이라는 것은 탐색하면서 방향을 트는 횟수가 최소가 되게 하면 된다는 것이다.

 

따라서 주어진 지도와 같은 크기의 turnCnt 배열을 생성한다.

 

탐색하는 과정에서 특정 위치 x, y에 도착하였을때 지금까지 방향을 몇 번 틀었나 체크를 해주게 되고, 이 방향 튼 횟수를 turnCnt[x][y]에 기록하면 된다.

 

글로 보면 이해가 안될것이다. 예제를 하나 들어보자.

 

예를 들어 아래와 같은 입력이 주어진다고 하자.

 

4 4
C.**
..**
....
...C

 

 

 

그리고 turnCnt 배열의 초기값은 최대값으로 해준다.

INT_MAX INT_MAX INT_MAX INT_MAX
INT_MAX INT_MAX INT_MAX INT_MAX
INT_MAX INT_MAX INT_MAX INT_MAX
INT_MAX INT_MAX INT_MAX INT_MAX

 

시작 위치는 왼쪽 상단 C 위치인 (0, 0) 부터 시작하여 도착 위치인 (3, 3)으로 이동하면서 체크해야 할 부분은 다음과 같다.

 

1, 4방향 탐색을 진행한다.

2. 다음 좌표에까지 방향 전환 횟수가 지금까지 오면서 꺽은 횟수보다 많거나 같으면 갱신하면서 재 탐색해준다.

3. 그렇지 않으면 이전으로 가서 다시 탐색한다.

 

[0, 2147483647, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]

[0, 1, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]

[0, 1, 2147483647, 2147483647]
[2147483647, 2, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 2147483647, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 2147483647, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 2147483647]
[2147483647, 2147483647, 2147483647, 2147483647]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[2147483647, 2147483647, 2147483647, 2147483647]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[2147483647, 2147483647, 2147483647, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[2147483647, 2147483647, 6, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[2147483647, 7, 6, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[7, 7, 6, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[7, 6, 6, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[7, 6, 6, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[4, 6, 6, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[4, 5, 6, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[4, 5, 5, 6]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 5, 5, 5]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[4, 2, 5, 5]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 5, 5]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 5, 5]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 5, 5]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 5, 5]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 5, 5]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 5]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[4, 5, 5, 5]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[4, 5, 5, 4]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[4, 5, 4, 4]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[4, 5, 4, 4]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[4, 2, 4, 4]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[3, 2, 4, 4]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[3, 2, 3, 4]

[0, 1, 2147483647, 2147483647]
[3, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[3, 2, 3, 3]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 3, 3]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 3, 3]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 2, 3]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 2, 2]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 2, 2]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 2, 2]
[3, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 2, 2]
[1, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 2, 2]
[1, 2, 3, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 2, 2]
[1, 2, 2, 3]

[0, 1, 2147483647, 2147483647]
[1, 2, 2147483647, 2147483647]
[1, 2, 2, 2]
[1, 2, 2, 2]

계속해서 백트래킹해주면서 탐색해주면 목적지에 최소 회전 값이 갱신되어 있을 것이다.

import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static StringTokenizer st = null;

    static final char EMPTY = '.';
    static final char WALL = '*';
    static final char C = 'C';
    static final int START = 0;
    static final int END = 1;
    static int w, h, idx;
    static char[][] map;
    static Point[] p;

    public static void main(String[] args) throws IOException {

        st = new StringTokenizer(br.readLine());
        w = Integer.parseInt(st.nextToken());
        h = Integer.parseInt(st.nextToken());
        p = new Point[2];
        map = new char[h][w];
        visited = new boolean[h][w];
        turnCnt = new int[h][w];
        idx = 0;

        for (int i = 0; i < h; i++) {
            String line = br.readLine();
            for (int j = 0; j < w; j++) {
                map[i][j] = line.charAt(j);
                if (map[i][j] == C) {
                    p[idx++] = new Point(i, j);
                }
            }
            Arrays.fill(turnCnt[i], Integer.MAX_VALUE);
        }
        min = Integer.MAX_VALUE;
        visited[p[START].x][p[START].y] = true;
        dfs(p[START].x, p[START].y,-1, 0);

        System.out.println(turnCnt[p[END].x][p[END].y] - 1);
    }

    static int[] dx = {0, 0, -1, 1};
    static int[] dy = {-1, 1, 0, 0};
    static boolean[][] visited;
    static int[][] turnCnt;
    static int min;

    private static void printMap(int[][] map)
    {
        for (int i=0; i<map.length; i++){
            System.out.println(Arrays.toString(map[i]));
        }
        System.out.println();
    }

    private static void dfs(int x, int y, int exDir, int turn) {
        if (x == p[END].x && y == p[END].y) {
            turnCnt[x][y] = turn;
            return;
        }

        turnCnt[x][y] = turn;

//        printMap(turnCnt);
        for (int dir = 0; dir < 4; dir++) {
            int nx, ny;

            nx = x + dx[dir];
            ny = y + dy[dir];
            if (0 <= nx && nx < h && 0 <= ny && ny < w && !visited[nx][ny]
            && map[nx][ny] != WALL)
            {
//                System.out.println(nx+" "+ny);
//                System.out.println("dir : "+dir +" exDir : "+exDir+" turn : "+turn+" turnCnt[nx][ny] : "+turnCnt[nx][ny]);
                visited[nx][ny] = true;
                if (dir == exDir)
                {
                    if (turnCnt[nx][ny] >= turn)
                    {
                        dfs(nx, ny, dir, turn);
                    }
                }
                else
                {
                    if (turnCnt[nx][ny] >= turn + 1)
                    {
                        dfs(nx, ny, dir, turn + 1);
                    }
                }
                visited[nx][ny] = false;
            }

        }


    }


    public static class Point {
        int x, y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}

SOLID - SRP ( 단일 책임 원칙 ) 에 대하여

OOP

단일 책임 원칙 (SRP)

SRP (Single Responsibility Principle ) 이란..?

직역하면 단일 책임 원칙이다. 사실 직관적인 단어라 어려운 부분이 없다고 생각했다. 하지만 예시를 확인해 봤을때 이게 뭔 말인가? 했다. 그래서 가지고 있던 책 중에 클린 코드를 확인 해보았다.

단일 책임 원칙은 클래스나 모듈을 변경할 이유가 단 하나뿐이어야 한다.

 

아! 나는 기존에 정의된 하나의 클래스에 하나의 책임만을 가져야 된다는 것보다 이게 더 직관적으로 와닿았다.

Dashboard라는 클래스를 예시로 설명해보겠다.

 

public class Dashboard extends JFrame implements MetaData
{
    public Componet getLastFocusComp()
    public void setLastFocus(Component lastFocus)
    public int getMajorVersionNum()
    public int getMinorVersionNum()
    public int getBuildNum()
}

여기서 Dashboard의 역할은 두 개로 가정한다. 소프트웨어 버전 정보를 추적, Dashboard는 스윙 컴포넌트를 관리. 하지만 소프트웨어는 출시될때마다 버전 정보가 변경되며, 스윙 코드를 변경할 때마다 버전 번호가 달라진다. 자, 그럼 여기서 코드를 변경해야 하는 이유가 두 가지나 된다는 것이다.

 

따라서 이 코드에서 냄새를 제거해보자. 변경되는 이유를 찾았으니, 버전 정보를 다루는 메소드를 추출해서 새로운 클래스를 생성해보자. 여기서 버전 정보를 관리하는 메소드는 아래와 같다. 이를 Version 클래스로 만들어보자.

 

public class Version {
    public int getMajorVersionNum()
    public int getMinorVersionNum()
    public int getBuildNum()
}

이렇게 만들어진 Version 클래스는 다른 애플리케이션에서도 충분히 쉽게 사용될 것이다.

 

많은 주니어 개발자들은 깨끗하고 체계적인 소프트웨어보다 돌아가는 소프트웨어에 초점을 맞추는데, 사실 이건 비교하면 잘 정리된 여러 개의 수납장에 물건을 정리해서 사용할 것이냐? 큰 서랍장 하나에 모든 물건을 던져놓고 쓸 것이냐? 이다. 느껴지지 않는가? 냄새나는 코드의 제거는 중요하다.

마음의 정화를 가져오는 SRP, PEACE

아마존 리눅스 서버 생성 시 꼭 해야 될 설정

AWS

자바 기반의 웹 애플리케이션으로 작동해야 하는 서버들은 필수적으로 해야될 설정이 있습니다.

 

  • Java 사용할 버전 설치
  • 타임존 변경
  • 호스트네임 변경

저는 실습과정에서 aws linux ami1를 선택해서 진행해야 했었는데 aws에서 더 지원하지 않는지, 목록에 존재하지 않았습니다.

따라서 aws linux ami2 를 선택하여 진행했고, 접속하여 확인해보니 Java 가 설치되지 않았습니다. 

 

기본적으로 서버의 시간은 미국 시간대입니다. 따라서 한국의 시간대로 변경해야 합니다.

 

호스트네임은 실무에 간다면, 수십대의 서버가 동작하기에 IP주소로 구분하는 것은 어렵습니다. 따라서 호스트네임을 필수로 등록해야 합니다.

 

Java Install

sudo yum install -y java-1.8.0-openjdk-devel.x86_64

 

위 명령어를 입력하면 Java 8 version 이 설치가 됩니다.

 

혹시 이전에 설치된 버전이 있다면 아래 명령어를 입력한 다음 사용할 버전을 선택해주시면 됩니다.

 

sudo /usr/sbin/alternatives --config java

 

서버에 사용하지 않는 버전이 존재한다면 아래 명령어를 입력하여 제거해주세요

 

sudo yum remove java-version-openjdk

 

version은 제거할 버전이 1.7.0 인 경우에 version 대신 1.7.0을 입력해주시면 됩니다.

 

타임존 변경

EC2 서버의 기본 타임존은 UTC이며, 한국과 9시간 차이가 발생합니다.

현재 서버의 타임존은 date 명령어로 확인할 수 있습니다. AWS의 EC2의 기본 로컬타임은 UTC로 설정이 됩니다.

 

따라서 Seoul 시간대로 변경해보겠습니다.

 

sudo rm /etc/localtime

sudo ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime

 

두 명령어를 입력하고 date 명령어로 확인했을 때 시간대가 일치하면 정상적으로 변경된 것입니다.

 

Hostname 변경

명령어를 실행하여 정규화된 이름을 입력해야 합니다.

 

sudo hostnamectl set-hostname webserver.mydomain.com

 

빨간 부분을 원하는 이름으로 변경하고 명령어를 입력합니다.

 

이렇게 다 해주시고 난 뒤에 재부팅 후 호스트 네임을 확인해보십시요.

위와 같이 변경했다면 webserver 까지만 보입니다.

 

sudo reboot

 

리루팅하시면 일정 시간 이후에 재부팅이 됩니다. 따라서 기다리셨다가 접속해보세요

 

/etc/hosts 에 변경된 hostname 등록

호스트 주소를 찾을 때 가장 먼저 검색해 보는 /etc/hosts 에 변경한 hostname 을 등록해야 합니다.

추후에 hostname을 등록하지 않음으로 발생하는 장애가 존재할 수 있기에 사전에 해소합시다.

 

sudo vim /etc/hosts

hostname에 이전에 변경한 이름을 등록해주고 저장합니다.

 

등록하고 나서

 

curl 등록한 호스트 이름

 

으로 조회했을 때 잘 못 등록했다면 Could not resolve host 에러가 발생하고

 

올바르게 등록된 경우는 Failed to connect to 에러가 발생합니다. 이는 아직 80 port 접근이 안된다는 것임으로 호스트 네임 등록이 잘 되었다는 의미입니다.

'AWS' 카테고리의 다른 글

AWS 데이터베이스 환경 세팅 ( AWS RDS )  (0) 2020.11.23

Visual Studio Code : Java 실행 시 한글 깨짐

카테고리 없음

Java를 Code Runner 로 실행하면 한글 인코딩 에러가 발생한다.

 

한시간동안 찾아보면서 문제점들을 찾아봤는데, Dfile 옵션을 줘도 소용이 없었다.

 

그러다 vs code java setting 관련 포스팅을 보게 되었는데 아주 간단하게 해결되었다.

 

java extension을 설치하게 되면 

위와 같이 Run | Debug 가 뜨는데, Run으로 실행하면 아주 잘 실행된다.

 

혹여 누가 나와 같은 문제점을 겪으면 스트레스 받지말고 해결하길 바란다.