티끌모아 로키산맥 🏔
search
로ᄏl
배움에 끝은 없다... 개발 또한 그러하다.
Today
Yesterday
java.lang.Exception: No runnable method 오류 해결법
테스트 코드를 실행하는데 다른 테스트코드는 괜찮았는데 저 테스트 클래스만 JUnit Vintage라는 오류가 발생했다. 이 문제를 해결해보고자 구글링을 해보았다. 먼저 JUnit5를 잘못 사용한 것이 아닌가? 하는 의심이 들었다.(실은 크게 잘못 사용할만한 부분이 없었다) 테스트코드에 대한 기초지식도 없었을 때, Junit5는 JUnit Vintage + JUnit Jupiter이다라고 하면서 공부했던 적이있는데, 어쨋거나 jUnit5의 두 요소중 하나의 요소만 테스트에 성공했으니 junit Vintage의 요소를 제대로 못받아 온게 아닌가... 즉 의존성 설정부분에서 실수한 것이 있을 것 같다는 생각이 들었다. 아래의 링크를 참조해서 설정을 해보았다.
위와 같이 의존성을 추가적으로 설정했다. 윗 글의 필자에 의하면 어떤 오류가 발생한다고 하는데, 나는 이전에 발생했던 오류가 동일하게 발생했다. 분명 이전까지 잘 돌아가던 테스트 코드이기도 했고, 의존성 변경에도 변화가 없는걸로 보아, 이 방법은 해결방법이 아니라고 생각하였다.
https://larva.tistory.com/entry/spring-boot-javalangException-No-runnable-methods
위 글은 테스트 메서드에 @Test 를 안붙여서 나와 같은 오류가 발생했다고 하는데, 나는 분명 모든 테스트 메서드를 @Test 어노테이션을 붙였다. 이 오류 케이스도 나의 문제가 아니였다.
의외로 이 오류가 발생한 원인은 간단했다. 제대로 동작하는 다른 테스트 코드들이랑 처음부터 비교해봤더니 오류가 발생하는 테스트 클래스에 'public' (접근자)이 붙어있다는 차이점이 있었다. 이유는 잘 모르겠지만 일단 다른 테스트 클래스처럼 public을 지우고 테스트를 실행해보았다.
그랬더니 앞서 발생했던 오류도 없어졌다. (아예 테스트 실행창에 JUnit Vintage, JUnit Jupite로 구분되서 출력되지도 않는다) https://effectiveprogramming.tistory.com/entry/package-private-class%EC%97%90-%EB%8C%80%ED%95%9C-unit-test-%EB%B0%A9%EB%B2%95
뭔가 직접적인 이유라고 하기에는 뭐하지만 위의 내용을 참조하면 좋은 것 같다. 내용을 조금 인용해보자면 다음과 같다.
설계를 하다보면 종종 상위의 인터페이스나 상위 클래스는 외부에 public으로 노출을 시키되, 하위의 구체 클래스들은 외부에 노출시키지 않아야 하는 경우가 있다. 이는 정보 은닉을 위한 좋은 설계 방법 중 하나이다. 이를 위해서 보통 하위의 구체 클래스들을 package private class(JAVA에서 접근자 키워드가 없이 선언되는 클래스)로 선언한다. 이렇게 하면 같은 패키지 내에서는 해당 클래스에 접근할 수 있어도 다른 패키지에서는 package private 클래스를 접근할 수 없으므로 오직 인터페이스나 상위 클래스를 이용할 수 밖에 없다. 따라서 하위 클래스들의 변경이나 추가와 같은 유연성이 보장된다.
하지만 문제는 package private class에 대한 Unit Test를 작성하는 일은 쉽지 않다는 점이다. 일반적으로 제품 코드와 유닛 테스트 코드는 분리되는 것이 좋다. 제품 코드와 유닛 테스트 코드가 같은 곳, 즉 같은 패키지 내에 존재하면 제품의 출시를 위해서 유닛 테스트 코드를 골라내는 작업이 필요하다. 또 제품 코드를 이해하기 위해서 소스를 뒤적이다 보면 유닛 테스트 코드가 함께 섞여 있어서 불편함을 겪게 된다. 그래서 일반적으로 제품 코드와 유닛 테스트 코드를 분리하여 두는데, 이렇게 되면 제품 코드와 유닛 테스트 코드의 패키지가 분리되면서 package private인 요소들에 대해서는 유닛 테스트가 접근할 수 없게 된다. 이렇게 되면 간접적으로 해당 요소들을 테스트해야 하는데 이는 매우 번거로운 작업이 된다.
오류에 관련된 포스팅들을 보다가 제목이 눈에 끌려서 보게되었다. 테스트 코드를 작성할 때, 캡슐화를 하다보니면 private method, private variable이 존재하게 되는데... 이 메서드나 변수를 테스트할 때, 사용할 수 없어서 어떻게 테스트를 해야하는지에 대한 고민들이 많았다. (내가 조언받은 방법으로는 더 많이 코드를 쪼개서 역할을 분담하므로서 public 인자로 바꿔가는 것이었다)
이 방법이 좋은지에 대해서는 확신은 못하겠지만, "이런 방법도 있구나?" 정도로 생각하면 좋을 것 같다.