Executando verificação de segurança...
2

Como desenvolver testes eficientes?

Olá a todos.

Venho trabalhando desde 2020 em uma empresa que fornece serviços de Pesquisa e Desenvolvimento (P&D) na área de inteligência artificial e visão computacional.

Hoje, para o software que vai realizar a computação da IA e resolver os problemas de visão computacional, utilizamos C++ e Python.

Recentemente, por volta do meio de 2023, a gente começou a trabalhar com APIs, também feitas em Python usando FastAPI, e a desenvolver front-ends usando React.js. Também estamos trabalhando com Java para desenvolvimento Mobile e Swift para iOS.

De 2020 para cá, aprendi muita coisa (ainda bem). Contudo, uma coisa que certamente não consegui desenvolver muito bem é a parte de teste de software. Uma das coisas que eu menos tenho conhecimento é sobre teste de software. Hoje, no projeto em que estou encarregado, a gente faz testes manuais, ou seja, a gente roda o software que precisamos em um computador de borda, que nada mais é do que um mini PC cujo hardware foi desenvolvimento focando nos modelos de inteligência artificial. Que são as famosas Jetson NVIDIA.

Então nosso processo de software hoje se reside em:

  1. Tem uma pessoa encarregada de pegar este computador e instalar o software do zero. Simulando um computador novo.
  2. Rodamos o software em um vídeo onde a gente sabe qual o comportamento esperado da IA nele.
  3. Conecta uma câmera na rede, ou no próprio computador.
  4. Roda o software novamente nessa câmera que está livestreaming o nosso escritório.

Esta é a nossa rotina de testes, porém, tenho plena certeza de que isso não é o ideal. Há formas de melhorar. A questão que fica é, como?

Eu sei que existem ferramentas como PyTest, GoogleTest para C++, e etc... Porém o que me falta é uma metodologia para saber:

  • o que eu preciso testar?
  • o que eu consigo automatizar?
  • como que eu vou testar?
  • quais testes eu preciso fazer?

Fazendo algumas buscas, eu encontrei este site que comenta sobreThe Four Levels of Software Testing:

  1. Unit Test
  2. Integration Test
  3. System Testing
  4. Acceptance Testing

Isso já me dá um norte de como eu posso estruturar o processo de teste. Entretanto, eu ainda não consigo ter claro na minha cabeça o que exatamente eu preciso testar.

Vou dar um exemplo:

A gente possui uma classe que lê uma câmera, através de um link RTSP ou arquivo de vídeo, essa classe lê os frames em uma thread para que sempre estejamos lendo o frame mais recente da câmera. Normalmente, os leitores de vídeo como OpenCV, ou até as próprias câmeras, possuem um buffer de frames, para algumas aplicações é crucial lermos o mais recente. Caso não seja possível ler o frame naquele momento, a gente cria um frame em preto e continua o streaming. O que nós precisamos é que este leitor sempre esteja operando. Contudo, se ele ficar mais do que 30 segundos sem ler nada, ele encerra a leitura.

Nesse exemplo, como que eu poderia testar o comportamento esperado? Uma das formas que eu vejo é utilizando um vídeo, criar o teste automatizado e fazer o assert se ele parou de rodar depois do tempo especificado. Porém, eu precisaria também testar com uma câmera real, e aí surge um grande problema, pois existem algumas possibilidades que podem ocorrer com uma câmera real que não são tão simples de replicar.

Outro exemplo:
O leitor de câmera acima, é um dos componentes que o meu software precisa. A gente possuem outros componentes que são classes que encapsulam o modelo de IA para fazer detecção de objetos em imagens, outro componente é um escritor de dados no formato de JSON. Este JSON possui o conteúdo da imagem, em base64, os objetos que foram detectados e a timestamp do evento que foi detectado.

Neste caso, eu acredito que se trata de um integration test.

Dado este contexto, minhas perguntas são:

  1. Quais metodologias de testes vocês adotam, no sentido de: o que eu vou testar e como eu vou testar.
  2. Eu comentei mais da parte de software embarcado, porém como que eu posso desenvolver testes para componentes de UI, no caso dos componentes de React.js. Existe metodologia para isso também?

Desde já agradeço a todos.

Carregando publicação patrocinada...
2

Rapaz, eu valorizo o seu esforço em explicar o problema, e o software no qual você trabalha é bem interessante. No entanto, o escopo das suas perguntas é bastante amplo, o que torna um pouco difícil responder.

Talvez pessoas com experiência em câmeras possam ajudar, mas eu não conheço muito sobre o tema. Também considere criar outro post para explorar apenas um dos exemplos nos quais você precisa de ajuda. Com um escopo menor, pode ser mais fácil obter ajuda.

Contudo, gostaria de dar algumas dicas mais genéricas:

  • Ao escrever funções, minimize os "side effects" e faça com que suas funções retornem valores sempre que possível. Assim, você pode testar as funções de forma isolada, constituindo a base para os seus testes unitários.

  • Utilize injeção de dependência e inversão de controle quando possível.

  • Codifique pensando em interfaces (ou algo semelhante, como traits ou classes abstratas). Dessa forma, nos seus testes, você pode trocar um objeto/classe real, como as câmeras, por outros de teste (como uma câmera virtual, por exemplo), através da injeção de dependência.

1

É que eu me empolgo rsrsrs, mas entendo, sempre me falam que preciso ser mais objetivo.

  • Ao escrever funções, minimize os "side effects" e faça com que suas funções retornem valores sempre que possível. Assim, você pode testar as funções de forma isolada, constituindo a base para os seus testes unitários.

Essa parte do side effect que você se refere, só para ter certeza, é:

A function is said to have a side-effect when the function changes a non-local state or when its output is not deterministic

Nesse caso de fato é uma coisa que é um pouco problemática. Pois normalmente as funções que a gente desenvolve alteram arrays que são fornecidos por referência. Mas entendo a motivação da sugestão, vou pensar em algumas formas de lidar com isso.

Codifique pensando em interfaces (ou algo semelhante, como traits ou classes abstratas). Dessa forma, nos seus testes, você pode trocar um objeto/classe real, como as câmeras, por outros de teste (como uma câmera virtual, por exemplo), através da injeção de dependência.

Bem interessante essa sua sugestão, acho que isso vai ser uma das minhas primeiras abordagens para começar a desenvolver testes.

Muito obrigado!

2

Nesse caso de fato é uma coisa que é um pouco problemática. Pois normalmente as funções que a gente desenvolve alteram arrays que são fornecidos por referência. Mas entendo a motivação da sugestão, vou pensar em algumas formas de lidar com isso.

Correto, isso é mesmo um side-effect. No entanto, é um side-effect que podemos testar. Por exemplo, passe um array para a função e depois verifique se o array contém o conteúdo esperado depois que a função for executada, assumindo que que o array resultante tem um valor deterministico.

Uma das maneiras teóricas de remover o side-effect desta função é fazê-la retornar outro array com o resultado esperado. Mas acredito que, no seu caso, não seria uma boa ideia, pois isso duplicaria o espaço em memória; esta técnica funciona melhor quando os objetos retornados são leves.

2

Olá.
Você disse que existem algumas possibilidades que podem ocorrer com uma camera real que não são tão simples de replicar.
Pode citar alguns exemplos?

Respondendo sua pergunta:

  1. Particularmente uso muito testes unitários, de integração e de aceitação. Geralmente a parte mais dificil é escrever o primeiro. Depois que ele está pronto os outros são mais simples.
    Acredito que tentar ver isso não como testes, mas como especificações/comportamentos que seu código deva ter, facilita encontrar o que você precisa testar. Tenta conversar com a pessoa que hoje faz esses testes e verifica o que ela valida. Pode ser um ponto de partida. Ou pode tentar automatizar o "caminho feliz" e depois levantar outras necessidades.

Pela sua descrição, seus testes possuem dependencias externas o que dificulta um pouco a implementação. Uma sugestão é trabalhar com "mock objects" ou monkeypatch de funções para tentar simular esse dispositivo. Não sei como você faz essa integração mas acredito que exista uma biblioteca que você possa simular as chamadas a ela. Se você criou uma abstração em cima dessa biblioteca fica mais fácil.

  1. Sim, existe sim. Nunca criei teste automatizado para react mas criei muitos para componentes vue. Dá uma olhada em https://testing-library.com/.
    Me ajudou muito a criar testes para componentes em vue usando jsdom para simular o browser. Obviamente não substitui um browser, mas para validar comportamento do componente é excelente. Deixa para testar no browser (também de forma automatizada) apenas o que não consegue rodar no jsdom. O motivo é velocidade. Se testar tudo no browser o tempo de execução e retorno do seu teste será maior e a tendencia é roda-los com menos frequencia. Com isso é legal testar apenas o que não conseguir testar de outra forma.
1
Você disse que existem algumas possibilidades que podem ocorrer com uma camera real que não são tão simples de replicar.
Pode citar alguns exemplos?

Alguns comportamentos:

  • A câmera pode enviar alguns frames com problema ao realizar o encoding do vídeo. Ao fazer o decoding, a imagem vai vir com diversos artefatos de compressão, assim que chamamos. Isso é bem complicado de detectar, ao menos eu não conheço uma forma fácil. Até onde eu saiba é só possível de ver visualmente.
  • A câmera pode não conseguir ler a imagem em um determinado momento. Agora, o que vai acontecer com a leitura é um processo complicado. Podem haver dois possíveis comportamentos: a thread de leitura de câmera vai ficar travado ao tentar ler o frame, ou ela pode jogar um frame vazio. Contudo, existe um terceiro comportamento que eu já observei alguns poucas vezes, que o leitor de video morre totalmente. Ele quebra e nada mais funciona. Nós utilizamos a OpenCV para realizar a leitura da câmera e esse problema é realmente difícil de detectar. Esse problema os desenvolvedores ainda não conseguiram resolver.

Cara, gostei do que você descreveu no item (1). Acho que um bom jeito é eu encarar isso com minha equipe como sendo um "projeto", em que a gente tem que levantar os requisitos e desenvolver código em cima.

Muito obrigado pela dica da lib, vou testar!

1

Entendi.
Quando você diz que é dificil de detectar é pq pelo código não tem como detectar ou é algo que acontece esporádicamente e vocês não conseguem simular com a câmera ? Se o problema for simulação você não consegue injetar frames problemáticos em um arquivo de vídeo e assim criar um teste automatico para validar a correção? Ou se o drive retorna alguma exceção ou código de rro, você pode fazer seu objeto mock lançar essa mesma exceção (ou retornar o código de erro) para conseguir criar seus testes.