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:
- Tem uma pessoa encarregada de pegar este computador e instalar o software do zero. Simulando um computador novo.
- Rodamos o software em um vídeo onde a gente sabe qual o comportamento esperado da IA nele.
- Conecta uma câmera na rede, ou no próprio computador.
- 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:
- Unit Test
- Integration Test
- System Testing
- 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:
- Quais metodologias de testes vocês adotam, no sentido de: o que eu vou testar e como eu vou testar.
- 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.
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.
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:
- 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.
- 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.