Estou escrevendo testes para uma função como a próxima:
def foo():
print 'hello world!'
Então, quando eu quiser testar essa função, o código será assim:
import sys
from foomodule import foo
def test_foo():
foo()
output = sys.stdout.getline().strip() # because stdout is an StringIO instance
assert output == 'hello world!'
Mas se eu executar nosetests com o parâmetro -s, o teste falha. Como posso capturar a saída com unittest ou módulo nariz?
python
unit-testing
nosetests
python-nose
Pedro valencia
fonte
fonte
with mock.patch('sys.stdout', new_callable=StringIO.StringIO):
pypi.python.org/pypi/mockRespostas:
Eu uso este gerenciador de contexto para capturar a saída. Em última análise, usa a mesma técnica que algumas das outras respostas, substituindo temporariamente
sys.stdout
. Eu prefiro o gerenciador de contexto porque ele envolve toda a contabilidade em uma única função, então eu não tenho que reescrever nenhum código try-finally e não tenho que escrever funções de configuração e desmontagem apenas para isso.Use-o assim:
Além disso, uma vez que o estado de saída original é restaurado ao sair do
with
bloco, podemos configurar um segundo bloco de captura na mesma função do primeiro, o que não é possível usando as funções de configuração e desmontagem, e fica prolixo ao escrever try-finalmente blocos manualmente. Essa capacidade foi útil quando o objetivo de um teste era comparar os resultados de duas funções entre si, em vez de algum valor pré-calculado.fonte
TypeError: unicode argument expected, got 'str'
(o tipo passado para impressão (str / unicode) é irrelevante).from io import BytesIO as StringIO
e no python 3 apenasfrom io import StringIO
. Pareceu corrigir o problema em meus testes, eu acho.strip()
ounicode
retornado deStringIO.getvalue()
?sys
. Com sua instrução de importação, você está criando uma variável local chamadastderr
que recebeu uma cópia do valor emsys.stderr
. Mudanças em um não se refletem no outro.Se você realmente deseja fazer isso, pode reatribuir sys.stdout para a duração do teste.
Se eu estivesse escrevendo este código, no entanto, preferiria passar um
out
parâmetro opcional para afoo
função.Então, o teste é muito mais simples:
fonte
StringIO
classe agora deve ser importada doio
módulo.from io import StringIO
funciona em python 2.6+.from io import StringIO
em python 2, obterá umTypeError: unicode argument expected, got 'str'
ao imprimir.with redirect_stdout(out):
saved_stdout = sys.stdout
, você sempre tem uma referência mágica para fazer issosys.__stdout__
, por exemplo, você só precisasys.stdout = sys.__stdout__
na sua limpeza.Desde a versão 2.7, você não precisa mais reatribuir
sys.stdout
, isso é fornecido por meio debuffer
flag . Além disso, é o comportamento padrão do nosetest.Aqui está um exemplo de falha em contexto sem buffer:
Você pode definir tampão através
unit2
flag de linha de comando-b
,--buffer
ou emunittest.main
opções. O oposto é conseguido por meio danosetest
bandeira--nocapture
.fonte
--nocapture
; em particular, se este sinalizador for definido, o modo buffer será desabilitado. Portanto, você tem a opção de ver a saída no terminal ou de testar se a saída é a esperada.Muitas dessas respostas falharam para mim porque você não pode
from StringIO import StringIO
no Python 3. Aqui está um trecho de trabalho mínimo baseado no comentário de @naxa e no Python Cookbook.fonte
No python 3.5 você pode usar
contextlib.redirect_stdout()
eStringIO()
. Aqui está a modificação em seu códigofonte
redirect_stdout()
eredirect_stderr()
retornar seu argumento de entrada. Então,with contextlib.redirect_stdout(StringIO()) as temp_stdout:
dá a você tudo em uma linha. Testado com 3.7.1.Estou apenas aprendendo Python e me deparei com um problema semelhante ao acima com testes de unidade para métodos com saída. Minha aprovação no teste de unidade para o módulo foo acima acabou ficando assim:
fonte
sys.stdout.getvalue().strip()
e não trapacear comparando com\n
:)from io import StringIO
Escrever testes geralmente nos mostra uma maneira melhor de escrever nosso código. Semelhante à resposta de Shane, gostaria de sugerir outra maneira de ver isso. Você realmente deseja afirmar que seu programa produziu uma determinada string ou apenas que construiu uma determinada string para a saída? Isso se torna mais fácil de testar, já que provavelmente podemos supor que a
print
instrução Python faz seu trabalho corretamente.Então, seu teste é muito simples:
Obviamente, se você realmente precisa testar a saída real do seu programa, fique à vontade para desconsiderar. :)
fonte
foo()
não fizer nada além de chamar a instrução print, provavelmente não é um problema.Com base na resposta de Rob Kennedy, escrevi uma versão baseada em classe do gerenciador de contexto para armazenar a saída em buffer.
O uso é como:
Esta é a implementação:
fonte
Ou considere usar
pytest
, ele tem suporte integrado para declarar stdout e stderr. Veja a documentaçãofonte
Ambos n611x007 e Noumenon já sugeriu o uso
unittest.mock
, mas esta resposta se adapta Acumenos de mostrar como você pode facilmente envolverunittest.TestCase
métodos para interagir com um zomboustdout
.fonte
Com base em todas as respostas incríveis neste tópico, foi assim que resolvi. Eu queria mantê-lo o mais estoque possível. I aumentou o mecanismo de teste de unidade usando
setUp()
a capturasys.stdout
esys.stderr
, adicionou novas APIs do assert para verificar os valores capturados contra um valor esperado e, em seguida, restaurarsys.stdout
esys.stderr
sobretearDown(). I did this to keep a similar unit test API as the built-in
unittestAPI while still being able to unit test values printed to
sys.stdoutor
sys.stderr`.Quando o teste de unidade é executado, a saída é:
fonte