Pergunta

Temos um sistema que possui alguns scripts bash em execução além do código Java.Como estamos tentando testar tudo que possa quebrar, e esses scripts bash podem quebrar, queremos testá-los.

O problema é que é difícil testar scripts bash.

Existe uma maneira ou prática recomendada para testar scripts bash?Ou deveríamos parar de usar scripts bash e procurar soluções alternativas que possam ser testadas?

Foi útil?

Solução 2

Recebi a seguinte resposta de um grupo de discussão:

É possível importar (incluir, o que quer que seja) um procedimento (função, qualquer que seja nomeado) de um arquivo externo. Essa é a chave para escrever um script de teste: você divide seu script em procedimentos independentes que podem ser importados para o script em execução e o script de teste e, em seguida, você tem seu script em execução o mais simples possível.

Este método é como injeção de dependência para scripts e soa razoável. É preferível evitar scripts bash e usar uma linguagem mais testável e menos obscura.

Outras dicas

Realmente existe um Shunit2, uma estrutura de teste de unidade baseada em Xunit para scripts de shell baseados em Bourne. Eu não usei sozinho, mas pode valer a pena conferir.

Perguntas semelhantes foram feitas antes:

TOQUE-Compliant Bash Testing: Bash System de testes automatizados

Toque, o protocolo de teste de qualquer coisa, é uma interface simples baseada em texto entre os módulos de teste em um chicote de teste. Tap começou a vida como parte do chicote de teste para Perl, mas agora tem implementações em C, C ++, Python, Php, Perl, Java, JavaScript e outros.

Epóxi é uma estrutura de teste Bash que eu projetei principalmente para testar outros softwares, mas também o uso para testar os módulos de bash, incluindo em si e Carton.

As principais vantagens são uma sobrecarga de codificação relativamente baixa, aninhamento ilimitado de afirmação e seleção flexível de afirmações para verificar.

Eu fiz um apresentação comparando -o a Beakerlib - Uma estrutura usada por alguns no Red Hat.

Nikita Sobolev escreveu uma excelente postagem no blog comparando algumas estruturas de teste de bash diferentes: Testando aplicativos Bash

Para o impaciente: a conclusão de Nikita era usar Morcegos Mas parece que Nikita perdeu o Core de morcegos O projeto que me parece o único a usar, pois o projeto BATS original não é mantido ativamente desde 2013.

Por que você diz que é "difícil" testar scripts de bash?

O que há de errado com os invólucros de teste como:

 #!/bin/bash
 set -e
 errors=0
 results=$($script_under_test $args<<ENDTSTDATA
 # inputs
 # go
 # here
 #
 ENDTSTDATA
 )
 [ "$?" -ne 0 ] || {
     echo "Test returned error code $?" 2>&1
     let errors+=1
     }

 echo "$results" | grep -q $expected1 || {
      echo "Test Failed.  Expected $expected1"
      let errors+=1
 }
 # and so on, et cetera, ad infinitum, ad nauseum
 [ "$errors" -gt 0 ] && {
      echo "There were $errors errors found"
      exit 1
 }

Eu gosto bastante shell2Junit, um utilitário para gerar saída do JUNIT a partir de testes de scripts do BASH. Isso é útil porque o relatório gerado pode ser lido por sistemas de integração contínua, como os plug-ins do JUNIT para Jenkins e Bamboo.

Enquanto Shell2Junit não fornece a estrutura abrangente de scripts de bash como Shunit2, permite que você tenha bons relatórios dos resultados do teste.

Tentar Bashtest. É uma maneira simples de testar seus scripts. Por exemplo, você tem do-some-work.sh que alteram alguns arquivos de configuração. Por exemplo, adicione nova linha PASSWORD = 'XXXXX' para configurar arquivo /etc/my.cfg.

Você escreve comandos bash linha por linha e verifica a saída.

Instalar:

pip3 install bashtest

Criar testes é um comandos apenas de gravação.

Arquivo test-do-some-work.bashtest:

# run the script  
$ ./do-some-work.sh > /dev/null

# testing that the line "PASSWORD = 'XXXXX'" is in the file /etc/my.cfg   
$ grep -Fxq "PASSWORD = 'XXXXX'" /etc/my.cfg && echo "YES"
YES

Executar testes:

bashtest *.bashtest

Você pode encontrar Alguns exemplos aqui e aqui

Talvez isso possa ser usado ou contribuído para

https://thorsteinssson.github.io/bash_test_tools/

Destinado a escrever resultados no protocolo TAP, que eu imagino ser bom para o IC e bom para aqueles que desejam ambientes de concha. Eu imagino que algumas coisas sejam executadas em ambientes de concha, para que alguns possam argumentar que devem ser testados em seu ambiente de concha.

Experimentar assert.sh

source "./assert.sh"

local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!

Espero que ajude!

Não acredito que ninguém falou sobre Osht! É compatível com Ambas Toque e Junit, é uma concha pura (ou seja, não há outros idiomas envolvidos), também funciona independente e é simples e direta.

Os testes se parecem com este (trechos retirados da página do projeto):

#!/bin/bash
. osht.sh

# Optionally, indicate number of tests to safeguard against abnormal exits
PLAN 13

# Comparing stuff
IS $(whoami) != root
var="foobar"
IS "$var" =~ foo
ISNT "$var" == foo

# test(1)-based tests
OK -f /etc/passwd
NOK -w /etc/passwd

# Running stuff
# Check exit code
RUNS true
NRUNS false

# Check stdio/stdout/stderr
RUNS echo -e 'foo\nbar\nbaz'
GREP bar
OGREP bar
NEGREP . # verify empty

# diff output
DIFF <<EOF
foo
bar
baz
EOF

# TODO and SKIP
TODO RUNS false
SKIP test $(uname -s) == Darwin

Uma corrida simples:

$ bash test.sh
1..13
ok 1 - IS $(whoami) != root
ok 2 - IS "$var" =~ foo
ok 3 - ISNT "$var" == foo
ok 4 - OK -f /etc/passwd
ok 5 - NOK -w /etc/passwd
ok 6 - RUNS true
ok 7 - NRUNS false
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
ok 9 - GREP bar
ok 10 - OGREP bar
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
not ok 13 - TODO RUNS false # TODO Test Know to fail

O último teste mostra como "não ok", mas o código de saída é 0 porque é um TODO. Pode -se definir detalhadamente também:

$ OSHT_VERBOSE=1 bash test.sh # Or -v
1..13
# dcsobral \!= root
ok 1 - IS $(whoami) != root
# foobar =\~ foo
ok 2 - IS "$var" =~ foo
# \! foobar == foo
ok 3 - ISNT "$var" == foo
# test -f /etc/passwd
ok 4 - OK -f /etc/passwd
# test \! -w /etc/passwd
ok 5 - NOK -w /etc/passwd
# RUNNING: true
# STATUS: 0
# STDIO <<EOM
# EOM
ok 6 - RUNS true
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
ok 7 - NRUNS false
# RUNNING: echo -e foo\\nbar\\nbaz
# STATUS: 0
# STDIO <<EOM
# foo
# bar
# baz
# EOM
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
# grep -q bar
ok 9 - GREP bar
# grep -q bar
ok 10 - OGREP bar
# \! grep -q .
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
not ok 13 - TODO RUNS false # TODO Test Know to fail

Renomeie -o para usar um .t extensão e coloque -o em um t subdiretório, e você pode usar prove(1) (parte de Perl) para executá -lo:

$ prove
t/test.t .. ok
All tests successful.
Files=1, Tests=13,  0 wallclock secs ( 0.03 usr  0.01 sys +  0.11 cusr  0.16 csys =  0.31 CPU)
Result: PASS

Definir OSHT_JUNIT ou passar -j Para produzir saída JUNIT. Junit também pode ser combinado com prove(1).

Eu usei esta biblioteca ambas as funções de teste, adquirindo seus arquivos e depois executando afirmações com IS/OK e seus negativos e scripts usando RUN/NRUN. Para mim, essa estrutura fornece o maior ganho para o mínimo de sobrecarga.

eu criei ShellSpec Porque eu queria uma ferramenta fácil de usar e útil.

Escrito por puro script de shell POSIX. Ele testou com muitas conchas mais do que Shunit2. Possui recursos poderosos do que os morcegos/morcegos-core.

Por exemplo, suporte de suporte aninhado, fácil de zombar/stub, fácil de pular/pender, testes parametrizados, número da linha de asserção, executar número por linha, execução paralela, execução aleatória, formatador de toque/junit, cobertura e integração de IC, perfil e etc. .

Veja a demonstração na página do projeto.

Eu tentei muitas das soluções apresentadas aqui, mas achei a maioria delas muito complicadas e difíceis de usar, então construí minha própria estrutura de testes: https://github.com/meonlol/t-bash

É apenas um arquivo no repositório que você pode simplesmente executar diretamente, com um conjunto básico de declarações de estilo JUnit.

Usei-o profissionalmente em vários projetos internos e consegui tornar nossos scripts bash superestáveis ​​e resistentes a regressões.

Você pode querer dar uma olhada no Bash_unit:

https://github.com/pgrange/bash_unit

Dar uma olhada em Total, é simples, extensível por muitos idiomas (Perl, Python, Ruby, Bash on Choice) e estrutura de plataforma cruzada (Linux, Windows) para testar qualquer aplicativo de linha de comando.

Eu achei difícil justificar o uso do Bash para scripts maiores quando Pitão tem vantagens tão grandes:

  • Tente/exceto permite escrever scripts mais robustos com a capacidade de desfazer alterações em caso de erro.
  • Você não precisa usar sintaxe obscura, como 'if [ x"$foo" = x"$bar"]; then ...'O que é propenso a erros.
  • Easidade fácil de opções e argumentos usando o getopt Módulo (e há um módulo ainda mais fácil para analisar argumentos, mas o nome me escapa).
  • O Python permite que você trabalhe com listas/ditos e objetos em vez de seqüências e matrizes básicas.
  • Acesso a ferramentas de idioma adequadas, como regex, bancos de dados (com certeza você pode colocar tudo no mysql comando em bash, mas não é a maneira mais legal de escrever código).
  • Não há necessidade de se preocupar em usar a forma correta de $* ou "$*" ou "$@" ou $1 ou "$1", espaços nos nomes de arquivos não é um problema, etc, etc. etc.

Agora eu só uso o Bash para os scripts mais simples.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top