JUnit을 적용하기 시작하면서 제일 처음 마주한 에러였다.

야심 차게 TDD 적용을 꿈꾸며

@Test 애노테이션을 넣고 실행했는데

다음과 같은 에러가 발생했다.

 

 

 

 

 

 

 

에러 로그

java.lang.ExceptionInInitializerError
	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:31)
	at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24)
	at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
	at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)
	at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
	at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createUnfilteredTest(JUnit4TestLoader.java:87)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:73)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:46)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:522)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: java.lang.IllegalStateException: Failed to find class [org.junit.runners.model.MultipleFailureException]: SpringJUnit4ClassRunner requires JUnit 4.9 or higher.
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<clinit>(SpringJUnit4ClassRunner.java:102)
	... 17 more

 

 

ExceptionInInitExceptionInInitializerError 라는

생소한 에러를 마주하니

당황스러웠다..

전혀 감이 안잡혔다.

 

그렇지만 차분하게 읽어보니

아주 아주 친절하게 해결방법이 

적혀있었다.

 

 

 

 

 

 

 

 

해결

 

 

에러 로그를 자세히 보니

SpringJUnit4ClassRunner requires JUnit 4.9 or higher.라는

내용이 친절하게 나와있다.

JUnit4를 사용하고 싶다면 4.9 이상의

버전으로 세팅되어 있어야 한다.

 

 

<dependency>
	<groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.9</version>
    <scope>test</scope>
</dependency>

 

위의 내용과 같이 

4.9 버전으로 세팅을 다시 해주니 

정상적으로 잘 작동하는 것을 확인할 수 있었다!

 

 

JUnit은 버전도 다양하고 호환성에

아주 예민한 패키지인 것 같다.

 

 


 

 

도움이 되었다면

로그인이 필요 없는 공감 버튼 꾹 눌러주세요! 

 

 

 

SpringJUnit4ClassRunner.class의 빨간 줄

 

Spring에 JUnit을 적용하기 위해서는 찾아보던 중

적용하기 위해서는 

RunWith(SpringJUnit4ClassRunner.class)

애노테이션을 클래스 위에 

선언해주어야 한다길래 

그대로 했더니 아래 캡처와 같이 빨간 줄이 떴다..

 

 

그리고 빨간줄이 없어지질 않는다!! ㅠㅠ

 

 

저렇게 이클립스상에 빨간 줄로 표시되는 경우는 보통

필요로 하는 내용과 다른 정보를 넣었거나

존재하지 않은 내용을 넣었거나..

어쨌든 무언가 틀렸다는 내용이다.

 

 

 

 

 

 

 

해결

 

관련해서 찾아보니

시스템이 정상적으로 돌아갈 정도로 

spring 프레임워크 환경을 구축했다고 해서 

JUnit을 사용할 수 있는 게 아니었다.

 

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.2.9.RELEASE</version>
</dependency>

 

JUnit을 사용하기 위해서는 

spring-test라는 이름의 의존성을 주입해주어야 한다.

 

 

나는 지금까지 JUnit을 고려하지 않았기 때문에

특별히 큰 문제없이 개발했을 뿐 

JUnit을 사용하기 위해서는 spring-test이 꼭 필요하다.

 

 


 

 

포스팅이 도움이 되었다면

로그인이 필요 없는 공감 버튼 꾹 눌러주세요! 

 

 

개발하고 있는 서버에 JUnit을 적용하고

Mock 클래스를 사용해서 MVC에 대한

테스트 환경을 구축하였더니

다음과 같은 에러가 발생하였다.

 

 

에러 콘솔 캡처

 

 

 

에러 로그

java.lang.NoClassDefFoundError: javax/servlet/SessionCookieConfig

…

Caused by: java.lang.ClassNotFoundException: javax.servlet.SessionCookieConfig
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 32 more

 

 

에러만 해석해보자면

JSP를 사용하기 위해 필요한 패키지인 servlet 안에

SessionCookieConfig 클래스가 없어서 나는 에러이다.

 

이런 문제는 보통 버전에서 오는 경우가 많은 것 같아서 

찾아보니 역시 버전 호환성의 문제였다.

 

 

 

 

 

 

 

나는 현재 servlet-api 2.5버전을 사용하고 있었는데 

너무 옛버전이라서 불가능하다고 한다.

 

 

Junit 사용 불가 버전

 

 

 

MockHttpSession을 사용하기 위해서는

최소 3.1.0 버전을 사용해야 한다.

 

메이븐에서 검색해보니 

dependency 작성 규칙도 바뀌어 있었다

2.5 버전은 확실히 너무 옛 버전인 것 같다...

 

 

 

해결

 

<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>3.1.0</version>
    <scope>provided</scope>
</dependency>

 

상위 버전으로 의존성만 변경하니 

문제없이 잘 작동한다.

 

 


 

 

 

 

포스팅이 도움이 되었다면

로그인이 필요 없는 공감 버튼 꾹 눌러주세요! 

 

 

 

 

문제

우분투를 설치하고 바로 Tomcat을 실행하면 이런 문구가 뜬다.

Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
At least one of these environment variable is needed to run this program

java를 설치하지 않았고 JAVA_HOME을 지정하지 않아기 때문!

 

 

Java 설치하기

요즘 Oracle JAVA 유료화가 이슈이기 때문에 나는 OpenJdk를 설치하기로 했다.

 

#openjdk-8 설치
kyome-was@kyome-was:~/tomcat/bin$ sudo apt-get install openjdk-8-jdk

#설치로그~~
# ...

#설치 버전확인 
kyome-was@kyome-was:~/tomcat/bin$ java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (build 1.8.0_212-8u212-b03-0ubuntu1.18.04.1-b03)
OpenJDK 64-Bit Server VM (build 25.212-b03, mixed mode)

#JAVA_HOME 확인
kyome-was@kyome-was:~/tomcat/bin$ echo $JAVA_HOME

kyome-was@kyome-was:~/tomcat/bin$ 

그러나 설치했다고 JAVA_HOME 이 지정되지는 않는다!

 

JAVA_HOME 지정하기

#jdk home 디렉토리 확인
kyome-was@kyome-was:~$ cd /usr/lib/jvm/java-8-openjdk-amd64
kyome-was@kyome-was:/usr/lib/jvm/java-8-openjdk-amd64$ 

kyome-was@kyome-was:~$ sudo nano /etc/profile

....
# 밑에 다음의 내용 추가
export JAVA_HOME=usr/lib/jvm/java-8-openjdk-amd64
#저장 후 종료

#수정내용 적용
source /etc/profile

#적용 경로 확인
kyome-was@kyome-was:~$ echo $JAVA_HOME
usr/lib/jvm/java-8-openjdk-amd64

 

 

 

 

struts 관련 xml이 컴파일되지 않을 경우 발생 에러
struts로 생성한 객체가 없는데 관련url로 호출할 떄 발생하는 것으로 보임

 


2019. 6. 20 ▒▒▒▒ 9:43:17 org.apache.catalina.core.StandardWrapperValve invoke
▒ɰ▒: Servlet.service() for servlet default threw exception
java.lang.NoClassDefFoundError: org/apache/struts2/util/ClassLoaderUtils
        at org.apache.struts2.codebehind.CodebehindUnknownHandler.locateTemplate(CodebehindUnknownHandler.java:256)
        at org.apache.struts2.codebehind.CodebehindUnknownHandler.handleUnknownAction(CodebehindUnknownHandler.java:99)
        at com.opensymphony.xwork2.DefaultUnknownHandlerManager.handleUnknownAction(DefaultUnknownHandlerManager.java:111)
        at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:182)
        at org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
        at org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
        at com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
        at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:553)
        at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
        at org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter.doFilter(StrutsExecuteFilter.java:93)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter.doFilter(StrutsPrepareFilter.java:91)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at com.dsunfold.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:61)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
        at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
        at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:291)
        at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:769)
        at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:698)
        at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:891)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
        at java.lang.Thread.run(Thread.java:619)

'Web 개발 > 간단한 팁' 카테고리의 다른 글

[팁] JUnit 에러 : java.lang.NoClassDefFoundError  (0) 2019.11.07
ASP include  (0) 2019.07.19
Ubuntu Timezone 설정하기  (0) 2018.07.31
AWS에 로컬 파일전송하기 (scp)  (0) 2018.07.29
[팁] JSP 현재 페이지 EL로 받기  (0) 2018.02.20

1. android.os.FileUriExposedException

 file:///storage/~~.jpg exposed beyond app through ClipData.Item.getUri()

간단한 예제를 따라하며 안드로이드 개발을 하던 중 예외가 발생해서 문제점을 찾아서 올립니다!


버튼을 누르면 카메라를 실행하는 부분을 구현하고 있었습니다...

세부적으로 말하자면 프래그먼트 상에 ImageButton을 생성하고 OnClick 메서드에 카메라를 실행하는 인텐트를 호출하는 그런 작업중이었어요

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_camera, container, false);

mPhotoButton = (ImageButton)v.findViewById(R.id.camera);

final Intent captureImage = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

Uri uri = Uri.fromFile(mPhotoFile); // --------
captureImage.putExtra(MediaStore.EXTRA_OUTPUT, uri); // --------


mPhotoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivityForResult(captureImage,REQUEST_PHOTO); // --------③

}
});

mPhotoView = (ImageView) v.findViewById(R.id.crime_photo);


}

저는 맨 처음 에러메시지와 표시해주는 코드라인을 따라가보니 ③에서 문제가 생겼다고 생각이 들었습니다. 


일단 어떤 에러때문에 어플리케이션이 작동을 안했는지 봐볼까요?


라는 메시지와 함께 그 아래로 쭉쭉.. 메시지를 출력해주더라고요 ㅠㅠ


다음의 내용들이 중요해보이는 메시지에요 세부 디렉토리는 잘라냈습니다


그런데 자세히 볼수록 ①, ②에서 문제가 있다는 생각이 들었고 찾아보니 FileUri 부분이 문제였습니다.

 

2. 해결

Android 7.0 부터 API정책의 변경

안드로이드 7.0 (누가) 부터 앱사이의 공유가 더 엄격해져서 file:// URI 가 직접 노출되지 않도록 content:// URI를 보내고 

이에 대해서 임시 액세스 권한을 부여하는 방식으로 변경되었다고 합니다. 

이에 대한 자세한 설명은 밑에 공식참고문서(구글번역기로 번역된 글입니다)를 보시됩니다.


앱 사이의 파일 공유


Android 7.0을 대상으로 하는 앱의 경우, Android 프레임워크는 앱 외부에서 file:// URI의 노출을 금지하는 StrictMode API 정책을 적용합니다. 파일 URI를 포함하는 인텐트가 앱을 떠나면 FileUriExposedException 예외와 함께 앱에 오류가 발생합니다.

애플리케이션 간에 파일을 공유하려면 content:// URI를 보내고 이 URI에 대해 임시 액세스 권한을 부여해야 합니다. 이 권한을 가장 쉽게 부여하는 방법은 FileProvider 클래스를 사용하는 방법입니다. 권한과 파일 공유에 대한 자세한 내용은 파일 공유를 참조하세요.

https://developer.android.com/about/versions/nougat/android-7.0-changes.html#accessibility



위에 설명에서와 같이 FileProvider클래스를 사용해서 content:// URI에 권한을 부여하는 방법을 보면 다음과 같습니다.


1. AndroidManifest.xml 수정

<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.bignerdranch.android.test.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>

2. res/xml/filepaths.xml 생성

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="storage/emulated" path="."/>
</paths>


3. Uri.fromFile(File mFile) 코드 대체

Uri uri = Uri.fromFile(mPhotoFile);


-> Uri uri = FileProvider.getUriForFile(getContext(), "com.bignerdranch.android.test.fileprovider", mPhotoFile);


*com.bignerdranch.android.test 부분은 개인의 도메인을 입력하시고 mPhotoFile 대신 생성한 파일 객체를 넣으시면 됩니다!

참고로 filepaths.xml과 AndroidManifest.xml 내부의 meta-data, android:resource="@xml/filepaths"가 일치해야합니다.





+ Recent posts

"여기"를 클릭하면 광고 제거.