| 1 | \chapter{Testes}\label{cap:testes}
|
| 2 |
|
| 3 | Este capítulo registra como o comportamento do Nexo é verificado. Como nos
|
| 4 | capítulos anteriores, o compromisso é com a honestidade: não se prescreve uma
|
| 5 | estratégia ideal, mas se descreve o estado da prática, o que cada tipo de teste
|
| 6 | é capaz --- e incapaz --- de detectar, e as lacunas assumidas explicitamente na
|
| 7 | Seção~\ref{sec:test-gaps}.
|
| 8 |
|
| 9 | O foco recai sobre a verificação automatizada. A validação com usuários reais
|
| 10 | não foi realizada neste trabalho: o envolvimento de participantes em uma
|
| 11 | aplicação de saúde mental exigiria aprovação prévia de comitê de ética em
|
| 12 | pesquisa, levantamento de pessoas com transtorno de forma a aplicar com elas,
|
| 13 | cujo todo o trâmite não coube no cronograma do projeto. Essa ausência de
|
| 14 | avaliação externa é retomada como limitação na Seção~\ref{sec:test-gaps}.
|
| 15 |
|
| 16 | Os dados quantitativos citados ao longo do capítulo referem-se ao estado do
|
| 17 | repositório em meados de outubro de 2026.
|
| 18 |
|
| 19 | \section{Vocabulário}\label{sec:test-vocab}
|
| 20 |
|
| 21 | Quatro termos delimitam o alcance dos testes descritos adiante: unitário,
|
| 22 | integração, \textit{job} e \textit{end-to-end} (E2E). Como os nomes e as
|
| 23 | fronteiras entre esses níveis variam entre autores, o Quadro~\ref{tab:test-vocab}
|
| 24 | fixa o sentido adotado neste trabalho e o relaciona aos níveis usuais da
|
| 25 | literatura.
|
| 26 |
|
| 27 | \begin{table}[H]
|
| 28 | \centering
|
| 29 | \caption{Vocabulário de testes adotado neste trabalho}
|
| 30 | \label{tab:test-vocab}
|
| 31 | \small
|
| 32 | \begin{tabular}{|p{2.8cm}|p{6.6cm}|p{4.2cm}|}
|
| 33 | \hline
|
| 34 | \textbf{Termo} &
|
| 35 | \textbf{O que exercita} &
|
| 36 | \textbf{Nível usual na literatura} \\
|
| 37 |
|
| 38 | \hline
|
| 39 |
|
| 40 | Teste unitário &
|
| 41 | Uma única função ou módulo, sem HTTP e sem banco de dados. &
|
| 42 | Teste de unidade. \\
|
| 43 |
|
| 44 | \hline
|
| 45 |
|
| 46 | Teste de integração &
|
| 47 | A aplicação HTTP real (rotas, validação, autenticação, controladores
|
| 48 | e serviços) sobre um banco de dados real; apenas o que sai do processo
|
| 49 | é simulado &
|
| 50 | Teste de integração, em nível de API. \\
|
| 51 |
|
| 52 | \hline
|
| 53 |
|
| 54 | Teste de \textit{job} &
|
| 55 | Um processador de tarefa em segundo plano, chamado diretamente com uma carga
|
| 56 | fabricada, sobre o banco real. &
|
| 57 | Teste de integração de componente assíncrono \\
|
| 58 |
|
| 59 | \hline
|
| 60 |
|
| 61 | Teste \textit{end-to-end} (E2E) &
|
| 62 | O aplicativo empacotado, em um dispositivo, ao longo de uma jornada real de
|
| 63 | usuário. &
|
| 64 | Teste de sistema. \\
|
| 65 |
|
| 66 | \hline
|
| 67 | \end{tabular}
|
| 68 | \source{Elaborado pelo autor (2026)}
|
| 69 | \end{table}
|
| 70 |
|
| 71 | \section{Estratégia de Verificação}\label{sec:test-strategy}
|
| 72 |
|
| 73 | O código-fonte do Nexo vive em um único repositório com dois projetos
|
| 74 | independentes: a API e o aplicativo móvel. O esforço de teste entre eles é
|
| 75 | deliberadamente assimétrico. A API possui uma suíte automatizada e é protegida
|
| 76 | por um portão de integração contínua; o aplicativo móvel é verificado
|
| 77 | majoritariamente de forma manual, com uma suíte \textit{end-to-end} fina por
|
| 78 | cima. Essa assimetria não é um descuido, e se justifica por duas prioridades.
|
| 79 | A primeira é a capacidade de trabalho limitada: manter uma suíte automatizada
|
| 80 | completa nas duas esferas excederia o disponível, e concentra-se o esforço onde
|
| 81 | o retorno é maior. A segunda é que a API concentra a validação, a autenticação,
|
| 82 | as regras de negócio e a persistência --- isto é, a garantia sobre a integridade
|
| 83 | dos dados registrados pelo usuário.
|
| 84 |
|
| 85 | A Tabela~\ref{tab:test-tooling} resume as ferramentas envolvidas e o ponto em que
|
| 86 | cada uma atua.
|
| 87 |
|
| 88 | \begin{table}[H]
|
| 89 | \centering
|
| 90 | \caption{Ferramentas de verificação}
|
| 91 | \label{tab:test-tooling}
|
| 92 | \small
|
| 93 | \begin{tabular}{|p{4.4cm}|p{4.0cm}|p{5.0cm}|}
|
| 94 | \hline
|
| 95 | \textbf{Finalidade} &
|
| 96 | \textbf{Ferramenta} &
|
| 97 | \textbf{Onde atua} \\
|
| 98 |
|
| 99 | \hline
|
| 100 |
|
| 101 | Execução de testes e asserções da API &
|
| 102 | Vitest &
|
| 103 | API \\
|
| 104 |
|
| 105 | \hline
|
| 106 |
|
| 107 | Requisições HTTP nos testes &
|
| 108 | Supertest &
|
| 109 | Dentro dos arquivos do Vitest \\
|
| 110 |
|
| 111 | \hline
|
| 112 |
|
| 113 | Cobertura de código da API &
|
| 114 | Vitest (\textit{coverage}) &
|
| 115 | API, sem limiar mínimo \\
|
| 116 |
|
| 117 | \hline
|
| 118 |
|
| 119 | Banco de dados de teste &
|
| 120 | PostgreSQL &
|
| 121 | \textit{Container} local durante desenvolvimento; serviço efêmero no CI \\
|
| 122 |
|
| 123 | \hline
|
| 124 |
|
| 125 | Testes \textit{end-to-end} móveis &
|
| 126 | Maestro &
|
| 127 | Dispositivo Android físico, via \textit{adb} \\
|
| 128 |
|
| 129 | \hline
|
| 130 |
|
| 131 | \textit{Lint} do aplicativo &
|
| 132 | ESLint (\texttt{expo lint}) &
|
| 133 | Manual, fora do CI \\
|
| 134 |
|
| 135 | \hline
|
| 136 |
|
| 137 | Integração contínua &
|
| 138 | GitHub Actions &
|
| 139 | API \\
|
| 140 |
|
| 141 | \hline
|
| 142 | \end{tabular}
|
| 143 | \source{Elaborado pelo autor (2026)}
|
| 144 | \end{table}
|
| 145 |
|
| 146 | \section{Suíte de Testes da API}\label{sec:test-api}
|
| 147 |
|
| 148 | A suíte automatizada concentra-se na API e cobre três frentes: os testes
|
| 149 | unitários, os testes de integração das rotas HTTP e os testes dos processadores
|
| 150 | de tarefas em segundo plano. No momento da redação, o diretório
|
| 151 | \texttt{api/tests} reunia 48 arquivos --- 17 unitários, 26 de rotas e cinco de
|
| 152 | \textit{jobs}. A execução e as asserções ficam a cargo do Vitest; as requisições
|
| 153 | HTTP são feitas pelo Supertest, que exercita a aplicação Express diretamente,
|
| 154 | sem abrir uma porta de rede, porém através de sua pilha HTTP real.
|
| 155 |
|
| 156 | \subsection{Organização e ferramentas}\label{sec:test-api-org}
|
| 157 |
|
| 158 | A configuração do Vitest (\texttt{api/vitest.config.ts}) divide a suíte em dois
|
| 159 | ``projetos''. O projeto \texttt{unit} seleciona os arquivos com o sufixo
|
| 160 | \texttt{.unit.test.ts} e não carrega configuração global alguma, de modo que
|
| 161 | esses testes dependem apenas das funções que exercitam. O projeto \texttt{db}
|
| 162 | seleciona os demais arquivos --- integração e \textit{job} ---, aplica um arquivo
|
| 163 | de configuração global, fixa um limite de tempo por teste e faz com que esses
|
| 164 | testes trunquem e repovoem o banco.
|
| 165 |
|
| 166 | A cobertura de código é apenas mensurada, não imposta: o relatório
|
| 167 | (\texttt{npm run test:coverage}) não possui limiar mínimo nem bloqueia a
|
| 168 | integração contínua. A verificação estática de tipos (\texttt{npm run typecheck})
|
| 169 | também roda em caráter consultivo no CI --- uma falha é registrada, mas não
|
| 170 | interrompe o \textit{deploy}.
|
| 171 |
|
| 172 | \subsection{Execução e banco de dados de teste}\label{sec:test-api-db}
|
| 173 |
|
| 174 | Os testes que dependem do banco rodam contra uma instância real do PostgreSQL
|
| 175 | --- e não contra um substituto em memória ---, em uma base dedicada de nome
|
| 176 | sufixado com \texttt{\_test}, criada por um pequeno script e materializada com
|
| 177 | \texttt{prisma db push}. O isolamento entre os casos é obtido por truncamento:
|
| 178 | antes de cada teste, uma rotina executa \texttt{TRUNCATE users CASCADE},
|
| 179 | removendo a tabela de usuários e, por cascata, todas as dependentes. Não há
|
| 180 | \textit{rollback} transacional nem banco efêmero por execução.
|
| 181 |
|
| 182 | O carregamento de dados é feito por funções auxiliares escritas à mão, e não por
|
| 183 | uma biblioteca de fábricas: um módulo compartilhado
|
| 184 | (\texttt{api/tests/test-helper.ts}) oferece as primitivas centrais --- cliente
|
| 185 | Prisma, limpeza da base, criação de usuário e geração de token ---, e cada
|
| 186 | arquivo define os \textit{seeders} de que necessita.
|
| 187 |
|
| 188 | A regra para o uso de dublês na API é: simula-se apenas o que deixa o processo;
|
| 189 | a aplicação e o banco permanecem reais. A camada de filas (BullMQ) é substituída
|
| 190 | globalmente por um substituto que registra os \textit{jobs} enfileirados,
|
| 191 | permitindo afirmar tanto a resposta HTTP quanto o trabalho em segundo plano
|
| 192 | agendado. O envio de arquivos e o cliente de armazenamento são substituídos por
|
| 193 | implementações controladas, e o disparo de e-mail e de notificações
|
| 194 | \textit{push} é simulado pontualmente, nos arquivos que os exercitam.
|
| 195 |
|
| 196 | Duas fronteiras permanecem deliberadamente reais: o acesso ao banco, via
|
| 197 | Prisma, nunca é simulado; tampouco a autenticação. Os testes geram tokens JWT
|
| 198 | válidos, assinados com o segredo de teste, e os enviam no cabeçalho de
|
| 199 | autorização, de modo que o \textit{middleware} de autenticação real seja
|
| 200 | executado. Essa escolha reduz o risco de um teste passar porém se comportar de
|
| 201 | maneira distinta em produção.
|
| 202 |
|
| 203 | \subsection{Tipos de testes}\label{sec:test-api-tipos}
|
| 204 |
|
| 205 | A suíte da API divide-se em três grupos, retomando o vocabulário do
|
| 206 | Quadro~\ref{tab:test-vocab}: unitários, integração e tarefas assíncronas. Cada
|
| 207 | grupo é descrito a seguir com o que exercita, o que detecta e o que escapa ao
|
| 208 | seu alcance.
|
| 209 |
|
| 210 | \subsubsection{Testes unitários}
|
| 211 |
|
| 212 | Os testes unitários exercitam uma única função ou módulo, sem HTTP e sem banco
|
| 213 | de dados. Concentram-se na lógica pura do sistema, em grande parte extraída
|
| 214 | deliberadamente de seus envoltórios de persistência para se tornar testável: os
|
| 215 | agregadores dos indicadores, os construtores dos relatórios e auxiliares
|
| 216 | compartilhados, como paginação e conversão de agendamento. Também cobrem o
|
| 217 | gerador de código de ativação, a validade de tokens, os serializadores e as
|
| 218 | regras de validação. Por serem rápidos e determinísticos, são o instrumento
|
| 219 | natural para fixar casos-limite --- fronteiras de janelas de tempo, margens de
|
| 220 | classificação e aritmética de paginação --- e servem como documentação
|
| 221 | executável dessas regras.
|
| 222 |
|
| 223 | A limitação desse nível é estrutural: ele só alcança a lógica isolada em uma
|
| 224 | costura testável. Sem o banco e a camada HTTP, a maior parte do comportamento
|
| 225 | permanece fora de alcance, e o nível pouco contribui, isoladamente, para a
|
| 226 | confiança geral na aplicação.
|
| 227 |
|
| 228 | \subsubsection{Testes de integração}
|
| 229 |
|
| 230 | Os testes de integração formam a maior parte da suíte. Cada um constrói a
|
| 231 | aplicação real, conecta um cliente Prisma real e a exercita via Supertest,
|
| 232 | afirmando tanto a resposta HTTP quanto o estado persistido. Eles percorrem o
|
| 233 | caminho completo de uma requisição --- roteamento, validação, autenticação,
|
| 234 | controladores, serviços e persistência --- e, por operarem sobre um PostgreSQL
|
| 235 | real, não sofrem o descolamento que afeta os substitutos. Afirmar a resposta e
|
| 236 | as linhas persistidas simultaneamente verifica o efeito da operação, e não
|
| 237 | apenas o valor de retorno.
|
| 238 |
|
| 239 | Em contrapartida, exigem infraestrutura em execução, são mais lentos e, por
|
| 240 | compartilharem a mesma base, rodam em série. O isolamento por truncamento é
|
| 241 | suficiente, porém menos rigoroso do que um \textit{rollback} transacional, pois
|
| 242 | um teste que falha no meio pode deixar resíduos.
|
| 243 |
|
| 244 | \subsubsection{Testes de tarefas assíncronas}
|
| 245 |
|
| 246 | Os testes de \textit{jobs} importam um processador do BullMQ e o chamam
|
| 247 | diretamente, com uma carga fabricada, contra o banco real. Cobrem o código que
|
| 248 | executa fora do ciclo requisição--resposta --- os \textit{workers} que geram
|
| 249 | exportações, enviam mensagens e recalculam indicadores ---, chegando, no caso
|
| 250 | da exportação, a descompactar o anexo produzido e inspecionar seu conteúdo.
|
| 251 |
|
| 252 | Como o processador é invocado diretamente, a maquinaria da fila em si ---
|
| 253 | agendamento, repetição, tentativas e ordenação --- permanece fora do alcance. A
|
| 254 | carga é fabricada à mão e, por isso, pode divergir daquela que o enfileirador
|
| 255 | realmente envia, sem que nada verifique uma contra a outra.
|
| 256 |
|
| 257 | \section{Verificação do Aplicativo Móvel}\label{sec:test-mobile}
|
| 258 |
|
| 259 | Em linha com a assimetria descrita na Seção~\ref{sec:test-strategy}, o
|
| 260 | aplicativo móvel passou a contar com testes unitários em estágio inicial, ainda
|
| 261 | em andamento e sem a cobertura da suíte da API. A verificação cotidiana
|
| 262 | permanece predominantemente manual, em um dispositivo físico, contra a pilha
|
| 263 | local em execução --- o aplicativo roda como \textit{build} de desenvolvimento
|
| 264 | do Expo, com dependências nativas do Android. Essa verificação captura o que os
|
| 265 | testes automatizados raramente alcançam --- problemas visuais, de leiaute e de
|
| 266 | desempenho no dispositivo ---, mas não é repetível, não protege contra
|
| 267 | regressões e permanece invisível à integração contínua.
|
| 268 |
|
| 269 | \subsection{Suíte \textit{end-to-end} (Maestro)}\label{sec:test-mobile-e2e}
|
| 270 |
|
| 271 | Sobre a verificação manual há uma suíte \textit{end-to-end} opcional, baseada
|
| 272 | no Maestro, ferramenta declarativa de automação de interface para dispositivos
|
| 273 | móveis. A suíte cobre uma única jornada central --- login, registro de humor e
|
| 274 | saída --- por três fluxos em YAML, marcados como \texttt{smoke} e executados
|
| 275 | por um pequeno \textit{harness} (\texttt{frontend/scripts/e2e.sh}), exposto
|
| 276 | como \texttt{npm run test:e2e}. Os fluxos são dirigidos por identificadores de
|
| 277 | teste (\texttt{testID}) inseridos no código, e não pelo texto visível, o que os
|
| 278 | torna mais robustos a mudanças de interface.
|
| 279 |
|
| 280 | A execução depende de um dispositivo Android físico conectado por \texttt{adb},
|
| 281 | de um \textit{build} de desenvolvimento, da API em funcionamento com um usuário
|
| 282 | de teste semeado e do Metro servindo o aplicativo; não há caminho sem cabeça
|
| 283 | nem integração ao CI, de modo que a suíte é executada manualmente e com pouca
|
| 284 | frequência. Cada fluxo limpa o estado do aplicativo e recarrega o
|
| 285 | \textit{bundle}, tornando a execução lenta, e a cobertura permanece fina: um
|
| 286 | único caminho feliz, sem casos de erro. A suíte não está integralmente verde no
|
| 287 | momento da redação: os fluxos de login e de saída passam, mas o de registro de
|
| 288 | humor falha ao adicionar um componente de humor, porque a tela correspondente é
|
| 289 | abandonada pelo aplicativo pouco depois de ser aberta --- causa ainda não
|
| 290 | identificada.
|
| 291 |
|
| 292 | \section{Integração Contínua}\label{sec:test-ci}
|
| 293 |
|
| 294 | A integração contínua do Nexo \cite{Humble_Farley_2011} é executada no GitHub
|
| 295 | Actions e testa somente a API, coerente com a estratégia assimétrica. O fluxo
|
| 296 | de implantação (\texttt{.github/workflows/deploy.yml}) dispara apenas quando há
|
| 297 | mudanças em \texttt{api}: sobe um PostgreSQL efêmero, instala as dependências,
|
| 298 | prepara a base de teste, executa a verificação de tipos em caráter consultivo e
|
| 299 | roda a suíte com o Vitest. A construção da imagem e a implantação em produção
|
| 300 | são condicionadas ao sucesso dessa etapa, de modo que uma suíte reprovada
|
| 301 | impede a publicação, conforme o Capítulo~\ref{sec:deploy-and-ci}. O aplicativo
|
| 302 | móvel permanece fora da integração contínua: \textit{lint} (\texttt{expo lint})
|
| 303 | e verificação de tipos (\texttt{tsc --noEmit}) são executados apenas
|
| 304 | manualmente, e a suíte \textit{end-to-end} não é disparada por fluxo algum.
|
| 305 |
|
| 306 | \section{Cobertura e Lacunas}\label{sec:test-gaps}
|
| 307 |
|
| 308 | Em síntese, a verificação automatizada cobre a superfície HTTP e a persistência
|
| 309 | da API, a sua lógica pura e os seus trabalhadores em segundo plano; a
|
| 310 | verificação do aplicativo móvel restringe-se, por ora, a uma jornada manual de
|
| 311 | fumaça e a testes unitários ainda em consolidação. Permanecem pouco cobertas a
|
| 312 | lógica do \textit{frontend} entre o nível de unidade e o \textit{end-to-end}, a
|
| 313 | maquinaria da fila em si (agendamento, repetições e ordenação) e os caminhos de
|
| 314 | erro do aplicativo.
|
| 315 |
|
| 316 | Persistem, ainda, três limitações que merecem registro. A primeira é a ausência
|
| 317 | de validação com usuários reais, motivada pelo trâmite de comitê de ética em
|
| 318 | pesquisa descrito na abertura deste capítulo: as especificações automatizadas
|
| 319 | atestam o comportamento programado, mas não a adequação do sistema às
|
| 320 | expectativas do público-alvo. A segunda é a cobertura de código medida, mas não
|
| 321 | imposta, o que orienta o trabalho sem jamais reprovar uma \textit{build} ou
|
| 322 | \textit{deploy}. A terceira são os riscos de descolamento já mencionados: os
|
| 323 | dados de teste escritos à mão em cada arquivo e a cópia espelhada dos tipos da
|
| 324 | API mantida no \textit{frontend} podem divergir da fonte de verdade sem que
|
| 325 | nenhum teste acuse. Essas lacunas são assumidas de forma explícita e refletem
|
| 326 | uma escolha de priorização, não uma garantia de ausência de defeitos, e que
|
| 327 | podem ser corrigidas em incrementos no futuro.
|