53

몇 가지 junit 테스트를 통해 리소스를 만들어야합니다.

이 논리를 구현하는 한 가지 방법은@Before@After접근.

내가 한 일은 재사용 될 유틸리티 클래스의 생성을 캡슐화하는 것이 었습니다. 예 :

class UserCreatorTestUtil implements AutoClosable {
  User create() {...}
  void close() {...}
}

요점은 객체를 닫는 것을 기억할 필요없이 객체 자체가 닫히는 것입니다.@After.

사용법은 다음과 같아야합니다.

@Test
void test() {
  try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
    User user = userCreatorTestUtil.create();
    // Do some stuff regarding the user's phone
    Assert.assertEquals("123456789", user.getPhone());
  }
}

문제는 junit의 assert 키워드가Error- 아니야.Exception.

자원을 사용하여 시험 사용이 "catch"할 것인가?Errorclose 메소드를 호출할까요?

*에서 답변을 찾을 수 없습니다.자원을 사용하여 시험 사용 설명서.


  • OT : 기록만을 위해서 :" 일부 리소스를 만드는 일부 junit 테스트가 있습니다 "그래서 당신은UnitTests, 네가 가진 것은모듈 테스트~을 사용하여UnitTest - 뼈대. - Timothy Truckle
  • @TimothyTruckle - 니트 따기 중 :일부 자원조롱당한 버전을 참조 할 수도 있습니다.이 버전은 모든 것이 의미를 갖기 위해 여전히 닫혀 있어야합니다. - Martin Ba
  • 오류와 예외 (대문자 E)는 모두 예외 (소문자 e)입니다. - immibis
  • @immibis하지만 Throwables를 대소 문자를 구분하지 않고 모호하지 않도록 지정할 수 있습니다. - Thilo
  • @Thilo 그러나 대소 문자를 구분하지 않는 언어는 말 그대로 사탄입니다. - immibis

5 답변


74

그것은하지 않는다.catch아무것도. 하지만finally모든 자원을 닫으십시오.

finally블록들오류가 발생해도 실행됩니다..


  • 아니요, 예외 / 오류에 대해 간단히 알지 못합니다. - Stephan Bijzitter
  • 네, 같은 방법으로 매뉴얼을 정리합니다.finally블록 할 것입니다. - Thilo
  • 제외하고는 마침내 잘 작동합니다.System.exit():stackoverflow.com/questions/14905006/… - Christophe Roussy
  • 그것은 행동한다.거의같은finally블록과는 달리,finally차단하면 모든 후속 작업을Throwableclose()작업을 추가하고억제 된기본 throwable에 던져 넣을 수 있습니다. 에이finally블록은 기본 throwable에 대한 지식이 없으므로이를 수행 할 수 없습니다. - Holger
  • @Holger : 글쎄, 그것은finally블록게다가~에catch블록은 실제로 아무것도 잡을 수 없습니다 (단지 기본 throwable과 rethrows를 기록합니다). 모든 "동작" finally 블록에서 발생합니다. 자세한 내용은 @Nicolas answer를 참조하십시오. - Thilo

37

기본의 의사 코드자원을 사용하여 시험 사용성명서는 (cfJava Language Specification §14.20.3.1) :

final VariableModifiers_minus_final R Identifier = Expression;
Throwable #primaryExc = null;

try ResourceSpecification_tail
    Block
catch (Throwable #t) {
    #primaryExc = #t;
    throw #t;
} finally {
    if (Identifier != null) {
        if (#primaryExc != null) {
            try {
                Identifier.close();
            } catch (Throwable #suppressedExc) {
                #primaryExc.addSuppressed(#suppressedExc);
            }
        } else {
            Identifier.close();
        }
    }
}

보시다시피 잡기Throwable아니Exception포함하는Error그러나오직 기본 예외를 얻기 위해서억제 된 예외로 자원을 닫는 동안 발생한 예외를 추가합니다.

또한 리소스가finally블록그들은 무슨 일이 있어도 닫힐 것이다.(단,System.exit물론 현재 실행중인 Java Virtual Machine을 종료 할 때)Error또는Throwable던졌습니다.


  • 운수 나쁘게,javac이 복잡한 형식 표준을 그대로 따른다. 그걸 고려해서finally결국 두 경우에 코드 중복을 통해 구현됩니다. 변수에 예외를 저장하고이를 테스트하는 것은 전혀 의미가 없습니다.null, 예외가 있는지 여부에 상관없이 이미 코드 경로에 의해 암시 된 경우 ... - Holger
  • @Holger : 예외가 있었는지 여부아니코드 경로에 의해 암시됩니다. 기억하십시오.finally예외가 있었는지의 여부와 관계없이 블록이 실행됩니다. 무슨 코드 중복을 의미합니까?Identifier.close()) 그리고 왜 당신을 괴롭 히 느냐? 리소스를 사용하여 재시도해야한다고 제안 하시겠습니까? - siegi
  • @siegi : 바이트 코드 수준에서finally따라서, afinally블록은 블록을 떠날 수있는 모든 코드 경로에 액션을 복사하여 컴파일되며 예외 처리기, 즉try { foo(); } finally { bar(); }~에 컴파일된다try { foo(); } catch(Throwable t) { bar(); throw t; } bar();,bar()호출 코드. 예외가 발생했는지 여부에 상관없이 코드 경로에 의해 암시됩니다. 즉 첫 번째bar();호출은 예외적 인 조건하에있는 호출이며, 두 번째 호출은 예외 조건입니다. - Holger
  • @시기 :에 의해 생성 된 코드javac이것의 결과로이 질문. 저의 대답에서 저는이 행동을 "어떻게javac내부적으로 ", 명명하지 않고"finally블록 (block) "이라고 말하면서,이 시점에서 정식 명세를 알지 못했기 때문에 간단히 말하면, 모든 것이 명확해진다. - Holger
  • @Holger : 아, 자바 코드 수준 (즉, 위에 짤린 코드)에서 코드 복제를 생각했지만 바이트 코드 수준에서는 생각하지 않았습니다. 나는 try-with-resources에 대한 특별한 경우 처리를하지 않는 것이 디자인의 결정이라고 생각한다.javac그러나 간단히 "desugar" 그것을 언어 명세에 따라 작성한 다음 JIT 컴파일러가 그 일을하도록하십시오. - siegi

13

자원을 사용해보십시오 (Try-with-resources)는 그 자체로 어떤 것도 잡아 내지 못합니다.

그러나catchtry-with-resources 블록의 끝까지 차단하고Throwable너는 좋아한다:

try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
  // ... Whatever
} catch (RuntimeException e) {
  // Handle e.
} catch (Exception | Throwable t) {
  // Handle t.
}


9

뒤에있는 생각try-with-resources리소스를 닫아야하는지 확인하는 것입니다.

기존의 문제try-catch-finally진술은 당신의try블록은 예외를 throw합니다. 이제는 보통 그 예외를finally블록.

이제 finally 블록에서도 예외가 발생한다고 가정합니다. 이 경우 try catch에 의해 throw 된 예외는잃어버린및에서 생성 된 예외finally블록이 전파됩니다.

try {
    // use something that's using resource
    // e.g., streams
} catch(IOException e) {
   // handle 
} finally {
    stream.close();
    //if any exception occurs in the above line, than that exception
    //will be propagated and the original exception that occurred
    //in try block is lost.
}

에서try-with-resources그만큼close()리소스의 메소드가 자동으로 호출되며,close()예외를 던집니다.finally에 도달하지 못하고 원래의 예외가 손실됩니다.

이것과 대조 :

try (InputStream inputStream= new FileInputStream("C://test.txt")){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

위의 코드 스 니펫에서close()메서드가 자동으로 호출되면close()메서드는 또한 모든 예외를 생성합니다. 예외는 자동으로 표시되지 않습니다.

참조 :Java 언어 사양 14.20.3


5

마지막에 대한 오해 : try-with-resources 않습니다.아니~을해라.잡기.

그것은 않습니다결정적인 마침내따라서 "문제"의 종류는 중요하지 않습니다.

자세한 내용은JLS자세한 내용은!


  • 그러나 catch가 수행되므로 원본 예외가 유지되는 경우이를 유지하고 후속 예외를 억제 된 예외로 추가 할 수 있습니다. - Mark Rotteveel

연결된 질문


관련된 질문

최근 질문