Preciso escrever testes JUnit para um aplicativo antigo mal projetado e escrevendo muitas mensagens de erro na saída padrão. Quando o getResponse(String request)
método se comporta corretamente, ele retorna uma resposta 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);
}
Mas quando obtém XML malformado ou não entende a solicitação, ele retorna null
e grava algumas coisas na saída padrão.
Existe alguma maneira de afirmar a saída do console no JUnit? Para capturar casos como:
System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
Respostas:
usar ByteArrayOutputStream e System.setXXX é simples:
casos de teste de amostra:
Eu usei esse código para testar a opção de linha de comando (afirmando que -version gera a string da versão, etc etc)
Editar: versões anteriores desta resposta são chamadas
System.setOut(null)
após os testes; Essa é a causa dos comentadores de NullPointerExceptions.fonte
NullPointerException
em outros testes depois de definir um fluxo de erro nulo, conforme sugerido acima (emjava.io.writer(Object)
, chamado internamente por um validador XML). Em vez disso, sugiro salvar o original em um campo:oldStdErr = System.err
e restaurá-lo no@After
métodoEu sei que este é um thread antigo, mas há uma boa biblioteca para fazer isso:
Regras do sistema
Exemplo dos documentos:
Também permitirá interceptar
System.exit(-1)
e outras coisas pelas quais uma ferramenta de linha de comando precisaria ser testada.fonte
Em vez de redirecionar
System.out
, refataria a classe que usaSystem.out.println()
passando aPrintStream
como colaborador e depois usandoSystem.out
na produção e um Test Spy no teste. Ou seja, use Injeção de Dependência para eliminar o uso direto do fluxo de saída padrão.Em produção
No teste
Discussão
Dessa forma, a classe em teste se torna testável por uma refatoração simples, sem a necessidade de redirecionamento indireto da saída padrão ou interceptação obscura com uma regra do sistema.
fonte
ConsoleWriter
é o assunto de teste,Você pode definir o fluxo de impressão System.out através de setOut () (e para
in
eerr
). Você pode redirecionar isso para um fluxo de impressão que grava em uma sequência e depois inspecioná-lo? Esse parece ser o mecanismo mais simples.(Eu recomendaria, em algum momento, converter o aplicativo em alguma estrutura de log - mas suspeito que você já esteja ciente disso!)
fonte
Um pouco fora do tópico, mas no caso de algumas pessoas (como eu, quando eu encontrei este tópico) estarem interessadas em capturar a saída de log via SLF4J, o JUnit do commons-testing
@Rule
pode ajudar:Isenção de responsabilidade :
log4j
,log4j2
elogback
estão disponíveis no momento, mas estou feliz para adicionar mais.fonte
A resposta do @dfa é ótima, então dei um passo adiante para tornar possível testar blocos de saída.
Primeiro eu criei
TestHelper
com um métodocaptureOutput
que aceita a classe chataCaptureTest
. O método captureOutput faz o trabalho de definir e derrubar os fluxos de saída. Quando a execuçãoCaptureOutput
dotest
método é chamado, ele tem acesso à produção gerar para o bloco de teste.Origem do TestHelper:
Observe que TestHelper e CaptureTest estão definidos no mesmo arquivo.
Em seu teste, você pode importar o captureOutput estático. Aqui está um exemplo usando o JUnit:
fonte
Se você estava usando o Spring Boot (você mencionou que está trabalhando com um aplicativo antigo, provavelmente não é, mas pode ser útil para outras pessoas), use org.springframework.boot.test.rule.OutputCapture da seguinte maneira:
fonte
Com base na resposta do @ dfa e outra resposta que mostra como testar o System.in , gostaria de compartilhar minha solução para fornecer uma entrada para um programa e testar sua saída.
Como referência, eu uso o JUnit 4.12.
Digamos que temos este programa que simplesmente replica entrada para saída:
Para testá-lo, podemos usar a seguinte classe:
Não vou explicar muita coisa, porque acredito que o código é legível e citei minhas fontes.
Quando o JUnit é executado
testCase1()
, ele chama os métodos auxiliares na ordem em que aparecem:setUpOutput()
, por causa da@Before
anotaçãoprovideInput(String data)
, chamado detestCase1()
getOutput()
, chamado detestCase1()
restoreSystemInputOutput()
, por causa da@After
anotaçãoNão testei
System.err
porque não precisava, mas deve ser fácil de implementar, semelhante ao testeSystem.out
.fonte
Você não deseja redirecionar o fluxo system.out porque ele redireciona para a JVM INTEIRA. Qualquer outra coisa em execução na JVM pode ser confusa. Existem melhores maneiras de testar a entrada / saída. Olhe para stubs / zombarias.
fonte
Exemplo completo do JUnit 5 para testar
System.out
(substitua a parte when):fonte
Você não pode imprimir diretamente usando system.out.println ou usando a API do logger enquanto estiver usando JUnit . Mas se você quiser verificar algum valor, basta usar
Irá lançar abaixo o erro de afirmação:
Seu valor deve ser 21,92. Agora, se você testar usando esse valor, como abaixo, seu caso de teste será aprovado.
fonte
pra fora
por erro
fonte
@Rule
, em vez de fazê-lo em linha em seu teste. Notavelmente, se sua afirmação falhar, a segundaSystem.setOut/Err
chamada não será alcançada.