Apesar de todos saberem que é importante e necessário testar seu software e muitos o fazem automaticamente há muito tempo, não há uma receita única para configurar um monte de produtos populares nesse nicho, como o (amado) GitLab e JUnit . Preencha esta lacuna!

Introdutório
Primeiro, descreverei o contexto:
- Como todos os nossos aplicativos funcionam no Kubernetes, consideraremos a execução de testes na infraestrutura apropriada.
- Para montagem e implantação, usamos o werf (no sentido de componentes da infraestrutura, isso também significa automaticamente que o Helm está envolvido).
- Não vou entrar nos detalhes da criação direta de testes: no nosso caso, o cliente grava os testes por conta própria e só garantimos que eles sejam executados (e o relatório correspondente está disponível na solicitação de mesclagem).
Como será a sequência geral de ações?
- Montagem do aplicativo - omitiremos a descrição deste estágio.
- Implante o aplicativo em um espaço para nome separado do cluster Kubernetes e inicie o teste.
- Procure artefatos e analise um relatório JUnit do GitLab.
- Exclua o espaço para nome criado anteriormente.
Agora - para a implementação!
Personalização
Gitlab ci
Vamos começar com o fragmento
.gitlab-ci.yaml
descrevendo a implantação do aplicativo e executando os testes. A listagem acabou sendo bastante volumosa, portanto, é completamente complementada com comentários:
variables:
Kubernetes
Agora, no diretório
.helm/templates
, crie um YAML com Job -
tests-job.yaml
- para executar os testes e os recursos do Kubernetes necessários. Veja as explicações após a listagem:
{{- if eq .Values.global.run_tests "yes" }} --- apiVersion: v1 kind: ConfigMap metadata: name: tests-script data: tests.sh: | echo "======================" echo "${APP_NAME} TESTS" echo "======================" cd /app npm run test:ci cp report.xml /app/test_results/${CI_COMMIT_REF_SLUG}/ echo "" echo "" echo "" chown -R 999:999 /app/test_results/${CI_COMMIT_REF_SLUG} --- apiVersion: batch/v1 kind: Job metadata: name: {{ .Chart.Name }}-test annotations: "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-weight": "2" "werf/watch-logs": "true" spec: activeDeadlineSeconds: {{ .Values.global.ci_timeout }} backoffLimit: 1 template: metadata: name: {{ .Chart.Name }}-test spec: containers: - name: test command: ['bash', '-c', '/app/tests.sh'] {{ tuple "application" . | include "werf_container_image" | indent 8 }} env: - name: env value: {{ .Values.global.env }} - name: CI_COMMIT_REF_SLUG value: {{ .Values.global.commit_ref_slug }} - name: APP_NAME value: {{ .Chart.Name }} {{ tuple "application" . | include "werf_container_env" | indent 8 }} volumeMounts: - mountPath: /app/test_results/ name: data - mountPath: /app/tests.sh name: tests-script subPath: tests.sh tolerations: - key: dedicated operator: Exists - key: node-role.kubernetes.io/master operator: Exists restartPolicy: OnFailure volumes: - name: data persistentVolumeClaim: claimName: {{ .Chart.Name }}-pvc - name: tests-script configMap: name: tests-script --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: {{ .Chart.Name }}-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Mi storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }} volumeName: {{ .Values.global.commit_ref_slug }} --- apiVersion: v1 kind: PersistentVolume metadata: name: {{ .Values.global.commit_ref_slug }} spec: accessModes: - ReadWriteOnce capacity: storage: 10Mi local: path: /mnt/tests/ nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - kube-master persistentVolumeReclaimPolicy: Delete storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }} {{- end }}
Quais recursos são descritos nesta configuração? Ao implantar, crie um namespace exclusivo para o projeto (isso também é indicado em
.gitlab-ci.yaml
-
tests-${CI_COMMIT_REF_SLUG}
) e
tests-${CI_COMMIT_REF_SLUG}
-o nele:
- ConfigMap com um script de teste;
- Trabalho com uma descrição do pod e a diretiva de
command
especificada, que apenas executa os testes; - PV e PVC , que permite armazenar dados de teste.
Preste atenção à condição introdutória com
if
no início do manifesto - portanto, outros arquivos YAML do gráfico Helm com o aplicativo devem ser agrupados na construção
reversa para que não sejam implantados durante o teste. Isto é:
{{- if ne .Values.global.run_tests "yes" }} --- {{- end }}
No entanto, se os testes
exigirem alguma infraestrutura (por exemplo, Redis, RabbitMQ, Mongo, PostgreSQL ...) - seus YAMLs poderão
ser desativados. Implante-os em um ambiente de teste ... é claro, aprimorando como quiser.
Toque final
Porque Até agora, como a montagem e a implantação usando werf
só funcionam no servidor de construção (com gitlab-runner) e o pod com testes é executado no assistente, você precisa criar o diretório
/mnt/tests
no assistente e entregá-lo ao corredor,
por exemplo, via NFS . Um exemplo detalhado com explicações pode ser encontrado na
documentação do
K8s .
O resultado será:
user@kube-master:~$ cat /etc/exports | grep tests /mnt/tests IP_gitlab-builder/32(rw,nohide,insecure,no_subtree_check,sync,all_squash,anonuid=999,anongid=998) user@gitlab-runner:~$ cat /etc/fstab | grep tests IP_kube-master:/mnt/tests /mnt/tests nfs4 _netdev,auto 0 0
Ninguém proíbe fazer uma bola NFS diretamente no corredor do gitlab e montá-la em cápsulas.
Nota
Você pode perguntar, por que complicar tudo com a criação de Job, se você pode simplesmente executar o script de teste diretamente no shell runner? A resposta é bastante trivial ...
Alguns testes requerem acesso à infraestrutura (MongoDB, RabbitMQ, PostgreSQL, etc.) para verificar a correção de trabalhar com eles. Tornamos os testes unificados - com essa abordagem, fica fácil incluir essas entidades adicionais. Além disso, temos uma abordagem
padrão na implantação (mesmo se estiver usando o NFS, montagem adicional de diretório).
Resultado
O que veremos quando aplicarmos a configuração preparada?
A solicitação de mesclagem mostrará estatísticas resumidas dos testes lançados em seu último pipeline:

Você pode clicar em cada erro aqui para obter detalhes:
Nota : Um leitor atento notará que estamos testando um aplicativo NodeJS e nas capturas de tela - .NET ... Não se surpreenda: assim como parte da preparação do artigo, não houve erros ao testar o primeiro aplicativo, mas foram encontrados em outro.Conclusão
Aparentemente, nada complicado!
Em princípio, se você já possui um construtor de shell e ele funciona, e não precisa do Kubernetes, executar o teste com ele será uma tarefa ainda mais simples do que a descrita aqui. E na
documentação do
GitLab CI, você encontrará exemplos para Ruby, Go, Gradle, Maven e outros.
PS
Leia também em nosso blog: