Introdução
Os testes transformam uma expectativa em evidência executável. Um teste focado chama um comportamento, compara o resultado real com o resultado esperado e torna as alterações futuras mais seguras ao detectar regressões automaticamente.
Você adicionará testes a uma biblioteca preparada de cálculo de frete. As funções de produção são intencionalmente pequenas para que você possa se concentrar em onde os testes Rust ficam, como as asserções comunicam expectativas, quais casos de limite são importantes e como o Cargo pode executar um alvo de teste por vez.
Adicione um teste unitário focado
Nesta etapa, você colocará um teste unitário ao lado do código da biblioteca e executará somente esse teste pelo nome.
O projeto está em /home/labex/project/shipping-quote. Entre nesse diretório:
cd /home/labex/project/shipping-quote
Antes de editar, examine o código-fonte curto da biblioteca. O comando sed -n '1,220p' será usado aqui apenas como visualizador somente leitura: -n impede a impressão automática, e 1,220p imprime explicitamente as linhas de 1 a 220. Esse intervalo é suficiente para exibir o arquivo completo sem abrir um editor:
sed -n '1,220p' src/lib.rs
A sintaxe escrita como #[...] é um atributo: metadados anexados ao item Rust que aparece imediatamente abaixo dele. O atributo #[cfg(test)] informa ao Rust que o módulo de testes seguinte deve ser compilado somente durante as compilações de teste. Um módulo é um contêiner nomeado para itens relacionados; o próximo Guided Lab ensina módulos como uma ferramenta geral de organização.
Dentro de mod tests, a palavra de caminho super representa o módulo pai, e * representa todos os nomes acessíveis desse módulo pai. Portanto, use super::*; disponibiliza as funções da biblioteca usando seus nomes curtos dentro do módulo de testes. Por fim, uma função marcada com #[test] se torna um teste que o Cargo pode localizar e executar.
Abra o código-fonte com o Nano:
nano src/lib.rs
Substitua // FIRST_UNIT_TEST por este teste curto:
#[test]
fn light_parcel_costs_five() {
assert_eq!(shipping_cost(3), 5);
}
assert_eq! compara as duas expressões recebidas. Se elas forem iguais, o teste continua; caso contrário, o teste falha e imprime os dois valores. Aqui, o teste registra que o custo de envio de um pacote de três quilogramas é de cinco unidades.
Salve com Ctrl+O, pressione Enter e saia com Ctrl+X. Passe o nome do teste depois de cargo test para executar somente os testes cujos nomes contenham esse texto:
cargo test light_parcel_costs_five
O Cargo compila a versão de teste e informa o teste unitário nomeado:
test tests::light_parcel_costs_five ... ok
test result: ok. 1 passed; 0 failed; ...
O prefixo tests:: mostra que o teste está dentro do módulo de testes local da biblioteca, e ok comprova que a asserção foi aprovada.
Cubra os casos de limite
Nesta etapa, você adicionará testes nos limites em que o comportamento do frete muda.
Um valor representativo como 3 comprova um ponto dentro do intervalo de pacotes leves, mas os erros costumam ficar escondidos nas extremidades. No match preparado, 1..=5 é um padrão de intervalo que corresponde a qualquer valor de um a cinco, incluindo os dois extremos. Ele reutiliza a notação de intervalo inclusivo dos laços em um novo contexto de padrões. A função tem um comportamento especial para zero e mantém a tarifa de cinco unidades até exatamente cinco quilogramas. Testar esses valores registra os dois limites.
Abra novamente a biblioteca:
nano src/lib.rs
Substitua // EDGE_UNIT_TESTS por dois testes curtos:
#[test]
fn empty_parcel_is_free() {
assert_eq!(shipping_cost(0), 0);
}
#[test]
fn five_kilograms_is_still_light() {
assert_eq!(shipping_cost(5), 5);
}
Cada teste descreve uma regra em seu nome e contém uma única asserção focada. Isso facilita localizar uma falha. Salve o arquivo e saia do Nano.
O filtro tests:: corresponde aos nomes completos dos testes no módulo local de testes unitários. Use-o para executar os três testes unitários, excluindo por enquanto o alvo separado de testes de integração:
cargo test tests::
A evidência esperada é a aprovação dos três testes unitários:
test tests::empty_parcel_is_free ... ok
test tests::five_kilograms_is_still_light ... ok
test tests::light_parcel_costs_five ... ok
test result: ok. 3 passed; 0 failed; ...
Juntos, os exemplos cobrem um valor comum e os dois limites importantes da regra de pacote leve.
Conclua um teste de integração
Nesta etapa, você testará a biblioteca por meio de sua interface pública, usando um arquivo separado.
Os testes unitários dentro de src/lib.rs ficam próximos da implementação e podem usar os itens internos do módulo pai. Os testes de integração ficam no diretório de nível superior tests/, são compilados como programas de teste separados e usam somente a interface pública da biblioteca, como faria um código externo. O nome do pacote shipping-quote torna-se o nome do crate Rust shipping_quote, com um sublinhado, no código-fonte. O próximo Lab consolida a terminologia de pacote, crate, módulo e visibilidade pública.
Examine a estrutura preparada do teste de integração:
sed -n '1,160p' tests/order_workflow.rs
Ela importa somente a função pública order_total, chama essa função para um pedido de 40 unidades e um pacote de três quilogramas e deixa uma asserção para você completar. Abra o arquivo:
nano tests/order_workflow.rs
Substitua a linha de asserção provisória que termina em // INTEGRATION_ASSERTION por:
assert_eq!(total, 45);
O total esperado combina o subtotal de 40 unidades com o custo de envio de cinco unidades para um pacote leve. Salve o arquivo e saia do Nano.
A opção --test order_workflow seleciona o alvo de teste de integração cujo arquivo é tests/order_workflow.rs:
cargo test --test order_workflow
O alvo informa o teste do fluxo público:
test order_total_includes_shipping ... ok
test result: ok. 1 passed; 0 failed; ...
Por fim, execute todo o conjunto de testes do pacote, sem filtro:
cargo test
O Cargo executa os três testes unitários e o teste de integração. É normal haver resumos de resultado separados, pois eles pertencem a binários de teste diferentes; todos os testes nomeados devem mostrar ok, e todos os resumos devem indicar zero falhas.
Resumo
Você adicionou testes unitários locais, cobriu os limites das regras, concluiu um teste de integração por meio da API pública da biblioteca e usou filtros do Cargo para executar um teste, um módulo, um alvo de integração ou o conjunto completo. Esses hábitos fornecem evidências rápidas durante o desenvolvimento e uma proteção mais ampla contra regressões antes da entrega.


