✅ Cap 21: Testes de Combate: Qualidade
🎯 Objetivo da Aula: Ao final desta aula, você entenderá o que são Testes de Unidade. Você aprenderá a criar pequenos scripts que verificam automaticamente se as contas do seu jogo (pontos, vida, dano) estão corretas, evitando que bugs cheguem aos jogadores.
🏢 O Cenário Prático (Seu Desafio):
Você mudou a regra de cálculo de dano, mas sem querer quebrou o sistema de cura! Agora os jogadores estão imortais. Seu desafio é criar um Escudo de Qualidade: uma bateria de testes que verifica se 10 de ataque - 2 de defesa dá exatamente 8 de dano. Se o resultado for diferente, o computador te avisa na hora!
🧠 Fundamentos: A Teoria Traduzida
📖 Dicionário do Programador
- Teste de Unidade: É testar uma “peça” (função) isolada do app.
- Assert (Afirmar): É o comando de verificação. “Eu afirmo que o resultado deve ser 10”. Se for 9, o teste falha.
- Mock (Dublê): Se sua função precisa de internet para ser testada, você usa um “servidor de mentira” para o teste ser rápido e não depender de Wi-Fi.
💡 Neste curso usamos o JUnit 5 (Jupiter) — a mesma versão usada no projeto P20 (Simulador de Batalha). Por isso
@TesteassertEqualsvêm do pacoteorg.junit.jupiter.api, não deorg.junit(JUnit 4). Mais adiante neste capítulo você também vai usar o MockK, a mesma biblioteca de Mock citada no Dicionário do Projeto de P20.
🎨 O Padrão de Teste (GIVEN / WHEN / THEN)
Organizamos o teste em 3 partes:
- Dado que (Given): Eu tenho um herói com 10 de força.
- Quando (When): Eu ataco um monstro.
- Então (Then): O monstro deve perder 10 de vida.
graph LR
A["Dados de Teste"] --> B(Sua Função)
B --> C[Resultado]
C --> D{Comparação: Assert}
D -->|Sucesso| E["✅ Teste Passou"]
📖 Exemplo Passo a Passo: Testando o Dano
- No Android Studio, abra a pasta
app/src/test/java/br.com.curso.pokedex. - Crie um arquivo chamado
CombateTest.kt.
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class CombateTest {
@Test
fun verificarCalculoDeDano() {
// GIVEN: Dado que o ataque é 10 e a defesa é 2
val ataque = 10
val defesa = 2
// WHEN: Quando calculamos o dano
val resultado = calcularDano(ataque, defesa)
// THEN: Então o resultado DEVE ser 8
assertEquals(8, resultado)
}
}
🛠️ Prática Obrigatória 1:
Escreva um teste de unidade para uma função chamada verificarVida. O seu teste deve garantir que, se a vida for 0, a função retorne o texto "GAME OVER".
🛠️ Prática Obrigatória 2:
Crie um teste que verifique se o XP ganho nunca é negativo. Se você tentar somar -50 de XP, o sistema deve ignorar e manter o XP atual.
🔑 Gabarito Passo a Passo:
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
@Test
fun seVidaForZero_DeveRetornarGameOver() {
val status = verificarVida(0)
assertEquals("GAME OVER", status)
}
@Test
fun seXpForNegativo_NaoDeveMudarOValor() {
val novoXp = adicionarXp(atual = 100, ganho = -50)
assertEquals(100, novoXp) // Não deve diminuir!
}
🚀 Desafio Avançado: Testando com Mock (MockK)
Até agora você testou funções puras (sem dependências externas). Mas e se a função que você quer testar precisar de outro componente — como um serviço que busca dados? Você não quer que seu teste dependa de internet ou de um servidor real. É aqui que entra o Mock: uma versão “de mentira” desse componente, criada com a biblioteca MockK.
📦 Dependência Gradle
dependencies {
testImplementation "io.mockk:mockk:1.13.8"
}
Imagine a interface abaixo, que representa um serviço que busca o recorde salvo:
interface RankingService {
fun buscarRecorde(): Int
}
fun bateuRecorde(servico: RankingService, pontuacaoAtual: Int): Boolean {
return pontuacaoAtual > servico.buscarRecorde()
}
Para testar bateuRecorde sem um RankingService real, criamos um Mock e dizemos o que ele deve responder:
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
class RankingTest {
@Test
fun seBaterRecorde_DeveRetornarTrue() {
// GIVEN: um RankingService de mentira que sempre retorna 100
val servicoFalso = mockk<RankingService>()
every { servicoFalso.buscarRecorde() } returns 100
// WHEN: o jogador faz 150 pontos
val resultado = bateuRecorde(servicoFalso, 150)
// THEN: 150 > 100, então bateu o recorde
assertTrue(resultado)
}
}
🛠️ Prática Obrigatória 3:
Usando o mesmo padrão, escreva um teste chamado seNaoBaterRecorde_DeveRetornarFalse. Configure o Mock para buscarRecorde() retornar 200 e verifique que bateuRecorde(servicoFalso, 150) retorna false (use assertFalse).
🔑 Gabarito Prática 3:
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Test
@Test
fun seNaoBaterRecorde_DeveRetornarFalse() {
val servicoFalso = mockk<RankingService>()
every { servicoFalso.buscarRecorde() } returns 200
val resultado = bateuRecorde(servicoFalso, 150)
assertFalse(resultado)
}
📤 Instruções de Entrega (Microsoft Teams):
- Envie o código da sua classe de teste.
- Nomeie como:
Gamer_SeuNome_Cap21.kt. - Submeta no canal de tarefas.