\chapter{Pruebas unitarias} \label{ch:unitarias} Las unitarias cubren \textbf{regresiones de dominio} sin levantar el stack completo. Un fallo aqu\'i suele ser m\'as barato de corregir que un fallo E2E. \section{Gateway} \begin{longtable}{@{}p{2.2cm}p{3.5cm}p{4.0cm}p{3.0cm}@{}} \caption{Unitarias gateway.}\\ \toprule \textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} & \textbf{Riesgo} \\ \midrule \endhead UT-GW-01 & Path upload vs JSON & Timeouts 600\,s vs 30\,s & Uploads cortados \\ UT-GW-02 & Health live sin upstream & \texttt{ok} inmediato & Orquestaci\'on ciega \\ UT-GW-03 & Health agregado degradado & Upstream down $\rightarrow$ \texttt{degraded} & Falsos ``todo ok'' \\ \bottomrule \end{longtable} \section{Bot-descarga API (\texttt{JobStore})} Cobertura en \texttt{test\_store.py}; ampliar con: \begin{longtable}{@{}p{2.4cm}p{3.4cm}p{3.8cm}p{3.0cm}@{}} \caption{Unitarias bot-descarga API.}\\ \toprule \textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} & \textbf{Riesgo} \\ \midrule \endhead UT-BOT-01 & Register + heartbeat & Online; offline $>$45\,s & Jobs a PCs muertos \\ UT-BOT-02 & Claim at\'omico & Un solo worker & Doble descarga \\ UT-BOT-03 & Cancel pending & \texttt{cancelled} & Jobs fantasma \\ UT-BOT-04 & Cancel running & \texttt{cancel\_requested} & Selenium sin freno \\ UT-BOT-05 & Auth Bearer & 401 si inv\'alido & Acceso indebido \\ UT-BOT-06 & Keys MinIO & Prefijos correctos & PDFs perdidos \\ \bottomrule \end{longtable} \section{Agent bot (PC)} Mantener y extender \texttt{bots/bot\_descarga/tests/}: \begin{longtable}{@{}p{2.6cm}p{4.0cm}p{5.5cm}@{}} \caption{Unitarias agent.}\\ \toprule \textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ \midrule \endhead UT-AGT-01 & Excel reader / NIT & Headers y limpieza correctos \\ UT-AGT-02 & PDF validator & Rechaza firmas/pesos inv\'alidos \\ UT-AGT-03 & Cancel mid-run & \texttt{should\_cancel} detiene loop \\ UT-AGT-04 & Browser fatal DNS & \texttt{fatal\_error} en Imaging \\ UT-AGT-05 & MinIO keys & Keys y modo an\'onimo \\ UT-AGT-06 & RemoteApiClient (mock) & register/claim/events con HTTP fake \\ \bottomrule \end{longtable} \section{Extraction / Cleaning / Count / Desktop} \begin{longtable}{@{}p{2.6cm}p{4.2cm}p{5.3cm}@{}} \caption{Unitarias resto de servicios.}\\ \toprule \textbf{ID} & \textbf{Caso} & \textbf{Criterio de \'exito} \\ \midrule \endhead UT-EXT-01 & Rate limiter LLM & Respeta RPM/TPM configurados \\ UT-EXT-02 & Normalizer JSON & Salida can\'onica estable \\ UT-CLN-01 & Reglas CSV & Numeric/text/special/dates \\ UT-CLN-02 & Type inference & Tipos coherentes con fixtures \\ UT-CNT-01 & Features ML & Vector de features esperado \\ UT-CNT-02 & PDF oversized & Rechazo controlado \\ UT-DES-01 & apiClient errores & Manejo de 4xx/5xx \\ UT-DES-02 & Wizard downloads & Payload job correcto \\ \bottomrule \end{longtable} \section{Comandos de ejecuci\'on} \begin{lstlisting}[language=bash,caption={Suite unitaria r\'apida}] cd bots/bot_descarga && python -m pytest tests/ -q cd services/bot_descarga && pytest -q cd services/desktop_app && npm test cd services/services-count-facturas-medicas-serving && go test ./... \end{lstlisting}