Eu tenho um módulo Python que usa a biblioteca argparse. Como escrevo testes para essa seção da base de código?
python
unit-testing
argparse
pydanny
fonte
fonte
foo()
é chamada". Zombar desys.argv
é a resposta, se for esse o caso. Dê uma olhada no pacote Python cli-test-helpers . Veja também stackoverflow.com/a/58594599/202834Respostas:
Você deve refatorar seu código e mover a análise para uma função:
Em sua
main
função, basta chamá-lo com:(onde o primeiro elemento
sys.argv
que representa o nome do script é removido para não enviá-lo como uma opção adicional durante a operação da CLI.)Em seus testes, você pode chamar a função analisador com qualquer lista de argumentos com a qual deseja testá-la:
Dessa forma, você nunca precisará executar o código do seu aplicativo apenas para testar o analisador.
Se você precisar alterar e / ou adicionar opções ao seu analisador posteriormente no seu aplicativo, crie um método de fábrica:
Posteriormente, você pode manipulá-lo, se quiser, e um teste pode se parecer com:
fonte
2
...argparse
não é muito amigável testar uma vez que imprime diretamente parasys.stderr
..."parte argparse" é um pouco vaga, então esta resposta se concentra em uma parte: o
parse_args
método. Este é o método que interage com sua linha de comando e obtém todos os valores passados. Basicamente, você pode simular o queparse_args
retorna, para que ele não precise realmente obter valores na linha de comando. Omock
pacote pode ser instalado via pip para versões python 2.6-3.2. Faz parte da biblioteca padrão a partirunittest.mock
da versão 3.3 em diante.Você precisa incluir todos os argumentos do seu método de comando,
Namespace
mesmo que não sejam passados. Dê a esses argumentos um valor deNone
. (consulte a documentação ) Esse estilo é útil para testar rapidamente casos em que valores diferentes são passados para cada argumento do método. Se você optar por zombar deNamespace
si mesmo por não ter total confiança em seus testes, verifique se ele se comporta de maneira semelhante àNamespace
classe real .Abaixo está um exemplo usando o primeiro trecho da biblioteca argparse.
fonte
argparse
e de suaNamespace
classe. Você deveria zombarNamespace
.from unittest import mock
é agora o método de importação correto - bem, pelo menos para python3Namespace
classe aqui é exatamente o que eu estava procurando. Apesar do teste ainda dependerargparse
, ele não se baseia na implementação específicaargparse
do código em teste, o que é importante para meus testes de unidade. Além disso, é fácil usarpytest
oparametrize()
método de testar rapidamente várias combinações de argumentos com uma simulação de modelo que incluireturn_value=argparse.Namespace(accumulate=accumulate, integers=integers)
.Faça com que sua
main()
função seja tomadaargv
como argumento, em vez de permitir que ela seja lidasys.argv
como será por padrão :Então você pode testar normalmente.
fonte
sys.argv.append()
e, em seguidaparse()
, ligue , verifique os resultados e repita.if __name__ == "__main__":
análise de chamada, faça o dump / avalie os resultados e teste-o em um arquivo em lotes / bash.fonte
Eu não queria modificar o script de veiculação original, então zombei da
sys.argv
parte em argparse.Isso é interrompido se a implementação do argparse mudar, mas o suficiente para um script de teste rápido. A sensibilidade é muito mais importante que a especificidade nos scripts de teste.
fonte
Uma maneira simples de testar um analisador é:
Outra maneira é modificar
sys.argv
e chamarargs = parser.parse_args()
Existem muitos exemplos de testes
argparse
emlib/test/test_argparse.py
fonte
parse_args
lança aSystemExit
e imprime em stderr, você pode pegar os dois:Você inspeciona stderr (usando,
err.seek(0); err.read()
mas geralmente essa granularidade não é necessária.Agora você pode usar
assertTrue
ou qualquer teste que desejar:Como alternativa, você pode capturar e repetir um erro diferente (em vez de
SystemExit
):fonte
Ao passar resultados de
argparse.ArgumentParser.parse_args
para uma função, às vezes uso umnamedtuple
para zombar de argumentos para teste.fonte
Para testar a CLI (interface da linha de comandos), e não a saída do comando , fiz algo parecido com isto
fonte