System.out.println ()에 대한 JUnit 테스트
제대로 설계되지 않았고 표준 출력에 많은 오류 메시지를 쓰는 오래된 응용 프로그램에 대해 JUnit 테스트를 작성해야합니다. 때 getResponse(String request)
방법이 제대로 작동 그것은 XML 응답을 반환합니다 :
@BeforeClass
public static void setUpClass() throws Exception {
Properties queries = loadPropertiesFile("requests.properties");
Properties responses = loadPropertiesFile("responses.properties");
instance = new ResponseGenerator(queries, responses);
}
@Test
public void testGetResponse() {
String request = "<some>request</some>";
String expResult = "<some>response</some>";
String result = instance.getResponse(request);
assertEquals(expResult, result);
}
그러나 XML 형식이 잘못되었거나 요청을 이해하지 못하면 null
일부 내용을 반환 하여 표준 출력에 씁니다.
JUnit에서 콘솔 출력을 주장하는 방법이 있습니까? 다음과 같은 경우를 잡으려면
System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
사용하여 있는 ByteArrayOutputStream을 하고 System.setXXX은 간단하다 :
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
private final PrintStream originalOut = System.out;
private final PrintStream originalErr = System.err;
@Before
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}
@After
public void restoreStreams() {
System.setOut(originalOut);
System.setErr(originalErr);
}
샘플 테스트 사례 :
@Test
public void out() {
System.out.print("hello");
assertEquals("hello", outContent.toString());
}
@Test
public void err() {
System.err.print("hello again");
assertEquals("hello again", errContent.toString());
}
이 코드를 사용하여 명령 행 옵션을 테스트했습니다 (-version이 버전 문자열 등을 출력하는지 확인).
편집 : 이 답변의 이전 버전은 System.setOut(null)
테스트 후에 호출 되었습니다. 주석가가 참조하는 NullPointerExceptions의 원인입니다.
나는 이것이 오래된 스레드라는 것을 알고 있지만 이것을 할 수있는 멋진 라이브러리가 있습니다.
문서의 예 :
public void MyTest {
@Rule
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
@Test
public void overrideProperty() {
System.out.print("hello world");
assertEquals("hello world", systemOutRule.getLog());
}
}
또한 System.exit(-1)
명령 줄 도구를 테스트해야하는 트랩 및 기타 사항 을 포착 할 수 있습니다.
리디렉션 대신에 공동 작업자로 전달 한 다음 프로덕션 에서 사용하고 테스트에서 테스트 스파이 를 사용하여 System.out
사용하는 클래스를 리팩터링합니다 . 즉, 표준 출력 스트림을 직접 사용하지 않으려면 Dependency Injection을 사용하십시오.System.out.println()
PrintStream
System.out
생산 중
ConsoleWriter writer = new ConsoleWriter(System.out));
시험에서
ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
ConsoleWriter writer = new ConsoleWriter(new PrintStream(outSpy));
writer.printSomething();
assertThat(outSpy.toString(), is("expected output"));
토론
이런 식으로 테스트중인 클래스는 표준 출력을 간접적으로 리디렉션하거나 시스템 규칙을 방해하지 않고도 간단한 리팩토링을 통해 테스트 할 수 있습니다.
setOut () 및 for in
및을 통해 System.out 인쇄 스트림을 설정할 수 있습니다 err
. 이것을 문자열로 기록하는 인쇄 스트림으로 리디렉션 한 다음 검사 할 수 있습니까? 가장 간단한 메커니즘 인 것 같습니다.
(어떤 단계에서 앱을 로깅 프레임 워크로 변환하는 것을 옹호하고 싶지만 이미 알고 있다고 생각합니다!)
주제를 약간 벗어 났지만 일부 사람들 (나와 같이이 스레드를 처음 발견했을 때)이 SLF4J를 통해 로그 출력을 캡처하는 데 관심이있는 경우 commons-testing 의 JUnit @Rule
이 도움이 될 수 있습니다.
public class FooTest {
@Rule
public final ExpectedLogs logs = new ExpectedLogs() {{
captureFor(Foo.class, LogLevel.WARN);
}};
@Test
public void barShouldLogWarning() {
assertThat(logs.isEmpty(), is(true)); // Nothing captured yet.
// Logic using the class you are capturing logs for:
Foo foo = new Foo();
assertThat(foo.bar(), is(not(nullValue())));
// Assert content of the captured logs:
assertThat(logs.isEmpty(), is(false));
assertThat(logs.contains("Your warning message here"), is(true));
}
}
면책 조항 :
- 본인의 요구에 맞는 솔루션을 찾을 수 없으므로이 라이브러리를 개발했습니다.
- 만에 바인딩
log4j
,log4j2
그리고logback
순간에 사용할 수있는,하지만 난 더 추가 할 수 기쁘게 생각합니다.
@ dfa 답변은 훌륭하므로 출력 블록을 테스트 할 수 있도록 한 단계 더 나아갔습니다.
먼저 성가신 클래스를 받아들이는 TestHelper
메소드로 만들었습니다 . captureOutput 메소드는 출력 스트림 설정 및 해제 작업을 수행합니다. 의 메소드 구현 이 호출되면 테스트 블록에 대한 출력 생성에 액세스 할 수 있습니다.captureOutput
CaptureTest
CaptureOutput
test
TestHelper의 소스 :
public class TestHelper {
public static void captureOutput( CaptureTest test ) throws Exception {
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
ByteArrayOutputStream errContent = new ByteArrayOutputStream();
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
test.test( outContent, errContent );
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.out)));
}
}
abstract class CaptureTest {
public abstract void test( ByteArrayOutputStream outContent, ByteArrayOutputStream errContent ) throws Exception;
}
TestHelper와 CaptureTest는 동일한 파일에 정의되어 있습니다.
그런 다음 테스트에서 정적 captureOutput을 가져올 수 있습니다. 다음은 JUnit을 사용하는 예입니다.
// imports for junit
import static package.to.TestHelper.*;
public class SimpleTest {
@Test
public void testOutput() throws Exception {
captureOutput( new CaptureTest() {
@Override
public void test(ByteArrayOutputStream outContent, ByteArrayOutputStream errContent) throws Exception {
// code that writes to System.out
assertEquals( "the expected output\n", outContent.toString() );
}
});
}
Spring Boot를 사용하고 있다면 (이전 응용 프로그램을 사용하고 있다고 언급 했으므로 아마도 그렇지는 않지만 다른 사람들에게 유용 할 수 있음) org.springframework.boot.test.rule.OutputCapture 다음과 같은 방식으로 :
@Rule
public OutputCapture outputCapture = new OutputCapture();
@Test
public void out() {
System.out.print("hello");
assertEquals(outputCapture.toString(), "hello");
}
@dfa의 답변 과 System.in 테스트 방법을 보여주는 또 다른 답변을 바탕으로 솔루션을 공유하여 프로그램에 입력하고 출력을 테스트하고 싶습니다.
참고로 JUnit 4.12를 사용합니다.
입력을 출력으로 간단히 복제하는이 프로그램이 있다고 가정 해 봅시다.
import java.util.Scanner;
public class SimpleProgram {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print(scanner.next());
scanner.close();
}
}
이를 테스트하기 위해 다음 클래스를 사용할 수 있습니다.
import static org.junit.Assert.*;
import java.io.*;
import org.junit.*;
public class SimpleProgramTest {
private final InputStream systemIn = System.in;
private final PrintStream systemOut = System.out;
private ByteArrayInputStream testIn;
private ByteArrayOutputStream testOut;
@Before
public void setUpOutput() {
testOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(testOut));
}
private void provideInput(String data) {
testIn = new ByteArrayInputStream(data.getBytes());
System.setIn(testIn);
}
private String getOutput() {
return testOut.toString();
}
@After
public void restoreSystemInputOutput() {
System.setIn(systemIn);
System.setOut(systemOut);
}
@Test
public void testCase1() {
final String testString = "Hello!";
provideInput(testString);
SimpleProgram.main(new String[0]);
assertEquals(testString, getOutput());
}
}
코드를 읽을 수 있다고 생각하고 소스를 인용했기 때문에 많이 설명하지 않습니다.
JUnit이 실행 testCase1()
되면 다음과 같은 순서로 헬퍼 메소드를 호출합니다.
setUpOutput()
@Before
주석으로 인해provideInput(String data)
에서 호출testCase1()
getOutput()
에서 호출testCase1()
restoreSystemInputOutput()
@After
주석으로 인해
필자가 System.err
필요로하지 않았기 때문에 테스트 하지 않았지만 testing과 비슷하게 구현하기 쉬워야한다 System.out
.
테스트 System.out
할 전체 JUnit 5 예제 (언제 부분 교체) :
package learning;
import static org.assertj.core.api.BDDAssertions.then;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class SystemOutLT {
private PrintStream originalSystemOut;
private ByteArrayOutputStream systemOutContent;
@BeforeEach
void redirectSystemOutStream() {
originalSystemOut = System.out;
// given
systemOutContent = new ByteArrayOutputStream();
System.setOut(new PrintStream(systemOutContent));
}
@AfterEach
void restoreSystemOutStream() {
System.setOut(originalSystemOut);
}
@Test
void shouldPrintToSystemOut() {
// when
System.out.println("example");
then(systemOutContent.toString()).containsIgnoringCase("example");
}
}
system.out 스트림을 리디렉션하지 않으려면 ENTIRE JVM에 대해 리디렉션해야합니다. JVM에서 실행중인 다른 것이 엉망이 될 수 있습니다. 입 / 출력을 테스트하는 더 좋은 방법이 있습니다. 스텁 / 모의를 살펴보십시오.
JUnit 을 사용하는 동안 system.out.println 또는 로거 API 를 사용 하여 직접 인쇄 할 수 없습니다 . 그러나 값을 확인하려면 간단히 사용할 수 있습니다.
Assert.assertEquals("value", str);
어설 션 오류 아래에 발생합니다.
java.lang.AssertionError: expected [21.92] but found [value]
값은 21.92 여야합니다. 이제 다음과 같이이 값을 사용하여 테스트하면 테스트 사례가 통과합니다.
Assert.assertEquals(21.92, str);
밖으로
@Test
void it_prints_out() {
PrintStream save_out=System.out;final ByteArrayOutputStream out = new ByteArrayOutputStream();System.setOut(new PrintStream(out));
System.out.println("Hello World!");
assertEquals("Hello World!\r\n", out.toString());
System.setOut(save_out);
}
실수
@Test
void it_prints_err() {
PrintStream save_err=System.err;final ByteArrayOutputStream err= new ByteArrayOutputStream();System.setErr(new PrintStream(err));
System.err.println("Hello World!");
assertEquals("Hello World!\r\n", err.toString());
System.setErr(save_err);
}
참고 URL : https://stackoverflow.com/questions/1119385/junit-test-for-system-out-println
'Programming' 카테고리의 다른 글
jQuery를 사용하여 입력 텍스트의 값을 설정하는 방법 (0) | 2020.03.04 |
---|---|
github의 특정 줄 번호에 연결하는 방법 (0) | 2020.03.04 |
VARCHAR과 CHAR의 차이점은 무엇입니까? (0) | 2020.03.04 |
안드로이드의 의도는 무엇입니까? (0) | 2020.03.04 |
일치하는 각 줄의 위와 아래에 grep을 어떻게 인쇄 할 수 있습니까? (0) | 2020.03.04 |