문제

https://www.acmicpc.net/problem/10527


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());

Map<String, Boolean> isDuplicate = new HashMap<>();
Map<String, Integer> domJudge = new HashMap<>();

for (int i = 0; i < n; i++) {
String input = br.readLine();

if (!isDuplicate.containsKey(input)) {
isDuplicate.put(input, false);
}

domJudge.put(input, domJudge.getOrDefault(input, 0) + 1);
}

Map<String, Integer> kattis = new HashMap<>();

for (int i = 0; i < n; i++) {
String input = br.readLine();

if (isDuplicate.containsKey(input)) {
isDuplicate.put(input, true);
}

kattis.put(input, kattis.getOrDefault(input, 0) + 1);
}

List<Map.Entry<String, Integer>> entries1 = new ArrayList<>(domJudge.entrySet());
List<Map.Entry<String, Integer>> entries2 = new ArrayList<>(kattis.entrySet());

entries1.addAll(entries2);
Collections.sort(entries1, (e1, e2) -> {
if (e1.getKey().compareTo(e2.getKey()) > 0) {
return 1;
} else if (e1.getKey().compareTo(e2.getKey()) < 0) {
return -1;
} else {
return Integer.compare(e1.getValue(), e2.getValue());
}
});

int answer = 0;
Set<String> set = new HashSet<>();
for (int i = 0; i < entries1.size(); i++) {
Map.Entry<String, Integer> entry = entries1.get(i);

if (isDuplicate.getOrDefault(entry.getKey(), false) && set.add(entry.getKey())) {
answer += entry.getValue();
}
}

System.out.println(answer);
}

흐름

  • 우선 이 문제는 domJudge와 kattis가 순서대로 n만큼씩 입력 받는 문제다.

예제를 보며 얘기하면

1
2
3
4
5
6
7
8
9
10
11
5
correct
wronganswer
correct
correct
timelimit
wronganswer
correct
timelimit
correct
timelimit

이렇게 되어 있을 때 위에 다섯 줄은 domJudge에서 채점한 결과고, 그 아래 다섯 줄은 kattis 채점한 결과다.

이걸 생각하고 프로그램을 작성하면

  1. 우선 양 쪽에서 채점된 결과들 중에 작은 녀석의 값을 골라야 하므로 채점 결과를 Key로 하는 Map을 만들고
  2. n 만큼 돌면서 domJudge의 채점 결과를 저장하는데 이 때 처음나온 채점 결과는 Map에 false로 저장하고, 이전에 이미 나온 결과는 +1 해준다.
  3. 그 후 다시 n만큼 돌면서 kattis의 채점결과를 저장하는데
  4. 이 때는 전에 domJudge에서 나온 채점 결과 인지 확인해야 하므로 중복을 체크하기 위해 만든 Map에 채점 결과가 존재하면 그 key의 값을 true로 변경시켜서 양 쪽에서 모두 나온 결과 임을 저장한다.
  5. 그 후 양 쪽에서 모두 나온 채점 결과들 중 작은 값들을 더하기 위해
  6. 두 Map을 리스트로 변환 후 합쳐서 key와 value로 sorting 한다.
  7. 그 후 합친 리스트를 반복하면서..
  8. 채점 결과가 양 쪽 모두에서 나온 녀석이면서 이전에 더한 key가 아니라면 쭉 더하고
  9. 출력하고 끝낸다.

결과


다른 분의 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine().trim();
int n = Integer.parseInt(line);
Map<String, Integer> map = new HashMap<>();
for(int i = 0; i < n; i++){
String dom = br.readLine();
map.put(dom, map.getOrDefault(dom, 0) + 1);
}
int cnt = 0;
for(int i = 0; i < n; i++){
String kattis = br.readLine();
if(map.containsKey(kattis) && map.get(kattis) > 0){
cnt++;
map.put(kattis, map.get(kattis) - 1);
}
}
System.out.println(cnt);
}
  • 나 처럼 바보 같이 Map을 여러 개 쓰지 않고 하나의 맵에 +1, -1로 해서 겹치는 결과 인지 아닌지 판단했다.
  • 나는 왜 이렇게 생각하지 못했을까? 다른 곳에서도 흔히 쓰이는 방식인데
  • 오늘도 역시 반성해본다…

댓글 공유

문제

https://www.acmicpc.net/problem/1417


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());

LinkedList<Integer> queue = new LinkedList<>();
int dasom = Integer.parseInt(br.readLine());
for (int i = 0; i < n-1; i++) {
int input = Integer.parseInt(br.readLine());

if (dasom <= input) {
queue.offer(input);
}
}

Collections.sort(queue);

int answer = 0;
for (; !queue.isEmpty() && queue.peekLast() >= dasom; answer++) {
if (queue.peek() < dasom) {
queue.poll();
}

queue.offer((queue.pollLast()-1));
dasom++;

Collections.sort(queue);
}

System.out.println(answer);
}

흐름

  1. 다솜이는 기호 1번이므로 첫 번째 입력을 다솜이의 표로 저장한다.
  2. 우선순위 큐로 사용하기 위해 list에 입력들을 저장하는데 다솜이 보다 작을 경우엔 문제의 답과 상관이 없으므로 다솜이의 표보다 적은 표는 큐에 저장하지 않는다.
  3. 우선순위 큐로서 동작하게 하기 위해 반복 전에 큐를 한번 정렬시켜준다.
  4. 그 후엔 큐가 비거나, 큐의 가장 큰 값이 다솜이가 될 때까지 반복한다.
  5. 반복하면서 큐의 맨 앞이 다솜이보다 작다면, 이제 그 사람은 다솜이가 재낀 것 이므로 큐에서 빼주고,
  6. 제일 표가 많은 놈한테서 표 하나를 뻇어서 다솜이가 가져가면 되므로 큐의 마지막 값에서 -1 빼서 다시 큐에 넣어준다.
  7. 그리고 제일 표가 많은 놈에게 뺏은 표를 다솜이에게 줬으므로 다솜이의 값을 1 증가시키고
  8. 우선순위 큐 처럼 동작 할 수 있게 큐를 다시 정렬 시킨다.
  9. 반복된 횟수를 출력하면 끝.

결과


여담

반복문에서 소팅을 하기 때문에 시간 초과가 날 것으로 예상했는데 수가 적은 문제라 그런지 무사히 통과되어 참 다행이다…

댓글 공유

서론

Front를 Vue.js, Back을 Spring Boot로 만든 토이 프로젝트에서 CORS로 인해 통신이 되지 않는 오류가 발생하여 문제를 해결한 방법을 작성 해둔다.


문제 상황

화면에서 체크박스를 클릭하면 서버로 requert를 보내고 서버에서 그에 맞는 response를 주는 방식에 간단한 프로젝트 인데 클릭 시 아래 이미지 처럼 ‘Network Error’라는 alert를 발생시키고 통신이 되지 않는 문제가 발생 하였고, 개발자 도구로 콘솔을 확인해보니 아래 이미지 처럼 ‘CORS Preflight Did Not Succeed’과

교차 출처 요청 차단: 동일 출처 정책으로 인해 http://localhost:9312/frame에 있는 원격 자원을 차단하였습니다. (원인: CORS 사전 점검 응답 실패).

라는 메시지가 출력된 것을 확인했다.


해결 방법

여러 가지 방법이 있겠지만 필자는 WebMvcConfigurer를 상속받아 설정을 추가해주는 방식으로 처리했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowCredentials(true);
}
}

  1. 위 코드 처럼 WebMvcConfigurer 를 상속받는 WebConfig class를 작성한다.
  2. 그 중 addCorsMappings() 메서드를 override 한다.
  3. CorsRegistry 클래스의 addMapping() 메서드를 통해 CORS 요청 처리를 활성화할 URL를 지정하는데 이 때 “/**” 같은 Ant 스타일 패턴이나 정확한 경로(ex /admin)를 지정하는 것도 가능하다.
  4. 그 후 allowedOrigins() 메서드에서 CORS 요청을 허용 할 URL를 지정한다.
  5. 참고로 allowCredentials 설정을 true로 줬는데 이렇게 Access-Control-Allow-Credentials를 true로 할 경우 allowedOrigins()에서 “*”로 해서 모든 요청에 대해 CORS를 허용 할 수 없다.

이 방법 외엔 @Crossorigin을 이용해 개별 클래스 혹은 메서드에 CORS 요청 인증을 응답하도록 설정 하는 것도 가능하다.

정상 동작한 모습


여담

이전에 개발 할 때는 설정하지 않아도 잘 됐던거 같은데 오랜만에 프로젝트를 클론받아 실행하니 동작하지 않아 당황했다… 왜 그럴까?


참고 사이트

댓글 공유

서론

집에서 서버에 접속할 일이 생겨서 평소처럼 ssh로 접속을 하려고 했는데..
접속이 되지 않아 당황했는데 미래의 나와, 다른 사람들은 이러지 않길 바라며 글을 남긴다.


접속 방법

우선 .pem 파일이 존재하는 경로에 폴더명이 한글인 폴더가 존재하면 안된다.

  1. 설정의 앱 및 기능에서 선택적 기능을 선택
  2. 기능 추가를 선택하여 ssh를 검색해서 OpenSSH 클라이언트를 설치
  3. SSH 이용 가능

여담

나의 경우엔 .pem 파일이 한글 폴더가 있는 경로에 존재해서 인식하지 못했던 문제였지만
혹시 모르니 SSH 클라이언트 설치방법도 작성해놓는다.

댓글 공유

문제

https://www.acmicpc.net/problem/4796


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

StringBuilder sb = new StringBuilder();
int i = 0;

String input = "";
while (!"0 0 0".equals(input = br.readLine())) {
int[] lpv = convertStringArrayToIntegerArray(input.split(" "));

int l = lpv[0];
int p = lpv[1];
int v = lpv[2];

sb.append("Case ").append(++i).append(": ").append((v/p) * l + ((v%p) > l ? l : (v%p))).append("\n");
}

System.out.println(sb);
}

private static int[] convertStringArrayToIntegerArray(String[] args) {
int[] array = new int[args.length];
int i = 0;
for (String str : args) {
array[i++] = Integer.parseInt(str);
}

return array;
}

흐름

  1. V일 중에 연속되는 P일 동안 L일 만큼 휴가를 사용 할 수 있으므로
  2. V에서 P를 나눈 값에서 L일을 곱하면 사용 가능한 휴가 일수가 구해지고
  3. L이 V일에서 P일을 나눈 값보다 작을 땐 L일 만큼 휴가를 더 갈 수 있고
  4. 큰 경우엔 V % P 일 만큼 갈 수 있으므로 구한 값을 더하면
  5. 총 휴가 일수를 구할 수 있다.

결과

댓글 공유

서론

사실, 제목이 결론이다. @Requestbody Annotation을 사용하려면 반드시 해당 DTO에는 기본 생성자가 명시적으로 존재하여야 한다. 뭔가 설정을 잘못했는지는 모르겠지만 intellij 에서 stacktrace가 출력되지 않아 이 사실을 알 수 가 없어서 엄청나게 삽질을 했기에 내용을 정리한다…


본론

상황

controller 테스트에서 모든 조건을 맞췄는데도 500 에러가 발생하여 테스트를 통과하지 못하는 상황이었는데 @Requestbody annotation을 DTO가 아닌 HashMap으로 변경하니 테스트가 정상적으로 통과되어 JSON이 제대로 DTO로 매핑되지 않아서 발생하는 문제라고 판단했다.

에러 발생

No suitable constructor found for type [simple type, class 클래스명]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)

직역하면 기본 생성자가 존재하지 않아서 에러가 발생했다는 내용이다.

해결 방법

빌더패턴을 사용하던 클래스에 @Noargsconstructor annotation을 사용해서 기본 생성자를 생성하게 하였다.

결론

@Requestbody와 DTO를 매핑되게 해야 할 경우 많은 조건이 필요하다.
이전 포스트에 작성했던 boolean의 변수명이라던가, 지금과 같은 기본 생성자라 라던지… 이게 모두 @Requestbody가 jackson 라이브러리를 이용해 매핑하기 때문이다.


참고 사이트

댓글 공유

서론

AWS 프리티어는 이미 다른 서비스가 이용하고 있고 Java를 지원해주는 클라우드 서비스가 없었는데 heroku를 발견하여 사용방법을 정리 해둔다.

참고로 데이터베이스는 한글을 지원하지 않는다.


본론

  1. heroku 회원 가입
  1. App 생성

위에 보이는 create a new app 버튼을 클릭하고

App name을 지정해야 하는데 이미 heroku에 존재하는 service의 name은 생성 할 수 없고,
여기서 지정한 App name으로 호스팅 될 URL이 생성된다.

  1. heroku CLI 설치

생성이 완료되면 위 화면처럼 Deploy tab으로 이동되는데 설명되어 있는 것 처럼 먼저 Heroku CLI를 자신의 OS 버전에 맞게 설치한다.

  1. Procfile 생성

Heroku는 실행 할 때 마다 port를 자동으로 지정해주는데 port를 고정시키기 위해 우선 application.properties에 port를 바인딩 해준다.

application.properties

1
server.port=${port:8080}

그 후 Procfile을 Project 루트 디렉토리에 확장자 없이 생성하고 아래와 같이 작성한다.

1
web: java -Dserver.port=$PORT $JAVA_OPTS -jar [실행될 jar파일 경로]

Procfile의 경로

  1. 배포

이후엔 heroku의 가이드를 그대로 따라하면 된다.

모든 가이드를 정상적으로 잘 따라하면 위 처럼 접속할 수 있는 URL이 출력되고 해당 URL로 접속하면

  1. 확인

https://backjoonframeautomaticgenerat.herokuapp.com/

정상적으로 실행되어 서비스가 실행되는 것을 확인 할 수 있다.


결론

데이터베이스를 사용하지 않는 서비스나, 한글이 입력되지 않는 서비스의 경우 무료로 이용 할 수 있는 좋은 클라우드 서비스 인 것 같다.

참고로 30분간 접속이 없으면 휴면 모드로 전환되어 최초 접속이 다소 느릴 수 있으나 무료 서비스인 만큼 그정도는 감안해주자.

이 글에 소개한 CLI를 이용한 방법 말고 Github와 연결해서 branch에 push하면 자동으로 배포되게 할 수 도 있는 것 같으니 찾아보고 적용하면 이 방법 보다 더 편할 것이다.


참고 사이트

댓글 공유

서론

연관관계에 있는 객체를 가져와서 set 하는 메서드를 테스트 하는 도중 아래와 같은 에러가 발생하였다.


본론

해당 에러

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.jjlee.wedding.payment.domain.Cost.costOptions, no session or session was closed

at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122)
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
at com.xxxxxx.ImplTest.가져와서_셋해야하는지_테스트(CostServiceImplTest.java:89)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

이 때 디버깅을 해보면 연결된 entitiy에서

1
Unable to evaluate the expression Method threw 'org.hibernate.LazyInitializationException' exception.

라는 에러가 발생해 있는데 이는 결국 select 한 entitiy가 영속성 컨텍스트 내에 존재하지 않기 때문에 발생한 애러이다.
위 에러에서 말하는 세션이 바로 영속성 컨텍스트를 말하는 것이고, 이는 한 트랜잭션안에 해당 entitiy가 존재하지 않다는 것과 같은 말이다.

해결

이를 해결하기 위해선 현재 지연로딩으로 되어있는 연관관계를 즉시로딩으로 변경하여 한번에 가져오던가,
혹은 Test 메서드에 @Transactional 어노테이션을 줘서 트랜잭션 내에 존재하도록 해주면 테스트가 정상적으로 통과되게 된다.

결과


참고 사이트

댓글 공유

서론

현재 작업 중인 프로젝트에서 테스트 코드를 작성해 테스트할 일이 있었는데 프로젝트의 환경은 spring 4.3에 Junit 4.8이었다.

이에 원래 사용하던 junit5로 넘어갈까 하였으나 junit5를 사용하려면 설정을 spring boot으로 해야 한다는 글들이 있어 같은 테스트 환경을 만들기 위해 junit만 4.12 버전으로 업그레이드한 후 테스트를 진행하였는데 spring 프로젝트지만 config 설정들을 boot 처럼 java 파일로 관리하는 형태여서 java 파일과 properties 파일을 동시에 잡아 줄 필요가 있었는데
@Contextconfiguration(classes = {블라블라…}, locations = {블라블라…})로 잡으니 에러가 발생하여 해결한 방법을 작성해놓는다.


본론

코드

1
2
3
4
5
6
7
@ContextConfiguration(classes = {
DatabaseConfig.class,
SecurityConfig.class,
SocialConfig.class,
EnumConfig.class,
WebMvcConfig.class
}, locations = "classpath:properties/test.properties")

서론에 적은 것 처럼 classes와 locations를 둘 다 설정하였더니 아래와 같이 에러가 발생하였다.

에러

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
java.lang.IllegalArgumentException: Cannot process locations AND classes for context configuration [ContextConfigurationAttributes@64c87930 declaringClass = 'com.xxxx.xxxImplTest', classes = '{class com.xxxx.config.DatabaseConfig, class com.xxx.config.SecurityConfig, class com.xxx.config.SocialConfig, class com.xxx.config.EnumConfig, class com.xxx.config.WebMvcConfig}', locations = '{classpath:properties/test.properties}', inheritLocations = true, initializers = '{}', inheritInitializers = true, name = [null], contextLoaderClass = 'org.springframework.test.context.ContextLoader']: configure one or the other, but not both.

at org.springframework.util.Assert.isTrue(Assert.java:68)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.processContextConfiguration(AbstractDelegatingSmartContextLoader.java:154)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:371)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:305)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildTestContext(AbstractTestContextBootstrapper.java:112)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:120)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:105)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTestContextManager(SpringJUnit4ClassRunner.java:152)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<init>(SpringJUnit4ClassRunner.java:143)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:37)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.internal.requests.ClassRequest.createRunner(ClassRequest.java:28)
at org.junit.internal.requests.MemoizingRequest.getRunner(MemoizingRequest.java:19)
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:36)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:49)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

해결

@Testpropertysource(classpath:””)로 test properties를 잡아주고
@Contextconfiguration(classes = { XXXConfig.class}) 로 Java config 파일들을 잡아준다.

1
2
3
4
5
6
7
8
@ContextConfiguration(classes = {
DatabaseConfig.class,
SecurityConfig.class,
SocialConfig.class,
EnumConfig.class,
WebMvcConfig.class
})
@Testpropertysource("classpath:properties/test.properties")

댓글 공유

서론

많은 블로그 서비스 중 필자는 Git, Github를 활용해서 사용하는 hexo로 github 블로그를 선택했지만, 다른 블로그 서비스들과는 달리 설치형 블로그의 특성상 설치된 PC가 아닌 경우엔 블로그에 글을 작성하는 일이 쉽지 않고, 블로그가 설치된 PC가 고장이라도 나는 날에는 고스라니 블로그를 날려버리는 상황이 닥치는 경우도 왕왕있다. (예로 필자는 블로그를 설치한 HDD가 고장나 블로그를 새로 작성했다.) 이런 경우를 방지하고, 블로그 작성의 확장성을 위해 github을 이용해 Hexo 블로그를 back up 하는 방법을 알아본다.


방법

post와 테마를 저장 할 저장소 생성
  1. 우선 위 사진처럼 github에서 테마와 post를 저장 할 repository를 생성한다.
    이 때 테마를 저장 할 저장소의 이름은 테마와 같게 한다.
설치한 테마의 저장소 변경
  1. 테마를 저장하기 위해 연결된 원격 저장소의 위치를 확인하고 설치한 테마 폴더 안에서 git 원격 저장소 주소를 변경한다.
  2. 변경 후 테마용 저장소에 테마를 push한다.
push 된 테마 확인
  1. 위 처럼 정상적으로 저장되어 있는지 확인하고 themes 폴더안에서 테마를 삭제한다.
  2. git의 submodule 기능을 이용해 저장한 테마를 submodule로 추가하는데 이 때 디렉토리의 위치는 themes 폴더 내로 이동해서 submodule 기능을 실행한다.
1
git submodule add 테마 저장소
  1. post를 저장 할 저장소 주소를 추가한다.(cotent)
1
git remote add content post 저장소
post 저장 확인
  1. post 저장용 저장소에 내용을 push하고 정상적으로 저장되었는지 확인한다.
  2. 이 후엔 post 작성 후 post만 content 저장소로 push해주면 된다.

결과

이제 우리는 불미스러운 사고로 블로그가 설치된 HDD가 고장나거나(ㅠㅠ), 블로그가 설치 안된 다른 PC or 노트북에서도 백업된 theme와 post들을 다운받아 블로그를 작성 할 수 있게 되었다.

여담이지만, 과거로 돌아간다면 나는 velog를 사용 할 듯 싶다.


참고 사이트

댓글 공유

Junggu Ji

author.bio


author.job