6. Testes
Testes são fundamentais para garantir a qualidade, confiabilidade e manutenibilidade de nosso software. Nossa estratégia de testes abrange vários níveis e tipos de testes, utilizando ferramentas modernas e práticas eficazes.
6.1. Tipos de testes
6.1.1. Testes Unitários
Testam unidades individuais de código (geralmente funções ou métodos) isoladamente.
Exemplo em Node.js (usando Japa):
import { test } from '@japa/runner'
import UserService from 'App/Services/UserService'
test.group('UserService', () => {
test('should create a new user', async ({ assert }) => {
const userService = new UserService()
const user = await userService.create({ name: 'John Doe', email: 'john@example.com' })
assert.equal(user.name, 'John Doe')
assert.equal(user.email, 'john@example.com')
})
})Exemplo em PHP (Laravel):
use Tests\TestCase;
use App\Services\UserService;
class UserServiceTest extends TestCase
{
public function test_it_creates_a_new_user()
{
$userService = new UserService();
$user = $userService->create(['name' => 'John Doe', 'email' => 'john@example.com']);
$this->assertEquals('John Doe', $user->name);
$this->assertEquals('john@example.com', $user->email);
}
}6.1.2. Testes de Integração
Testam a interação entre diferentes partes do sistema.
Exemplo em Node.js (Japa):
import { test } from '@japa/runner'
import { createUser, getUserById } from 'App/Services/UserService'
test.group('User Integration', () => {
test('should create and retrieve a user', async ({ assert }) => {
const createdUser = await createUser({ name: 'Jane Doe', email: 'jane@example.com' })
const retrievedUser = await getUserById(createdUser.id)
assert.equal(retrievedUser.name, 'Jane Doe')
assert.equal(retrievedUser.email, 'jane@example.com')
})
})Exemplo em PHP (Laravel):
use Tests\TestCase;
use App\Models\User;
class UserIntegrationTest extends TestCase
{
public function test_it_creates_and_retrieves_a_user()
{
$user = User::factory()->create([
'name' => 'Jane Doe',
'email' => 'jane@example.com'
]);
$response = $this->get("/api/users/{$user->id}");
$response->assertStatus(200)
->assertJson([
'name' => 'Jane Doe',
'email' => 'jane@example.com'
]);
}
}6.1.3. Testes End-to-End (E2E)
Testam o fluxo completo da aplicação, simulando interações do usuário.
Importante: Todas as tarefas devem incluir testes E2E utilizando EndTest. Os desenvolvedores são responsáveis por criar e manter estes testes como parte do processo de desenvolvimento.
Exemplo de cenário de teste E2E no EndTest:
- Abrir a página de login
- Inserir credenciais válidas
- Clicar no botão de login
- Verificar se o usuário foi redirecionado para o dashboard
- Criar um novo item
- Verificar se o item aparece na lista
- Fazer logout
6.2. Frameworks e ferramentas de teste
- Node.js: Japa para testes unitários e de integração
- PHP (Laravel): PHPUnit (integrado ao Laravel)
- E2E: EndTest
- Cobertura de código: Codecov
6.3. Cobertura de código
Utilizamos o Codecov para monitorar a cobertura de código de nossos testes.
Diretrizes de cobertura:
- Mínimo de 80% de cobertura para código novo
- Manter ou aumentar a cobertura geral do projeto
Configuração do Codecov (exemplo para .codecov.yml):
coverage:
status:
project:
default:
target: 80%
patch:
default:
target: 80%6.4. Testes de performance
Realizamos testes de performance para garantir que nossa aplicação atenda aos requisitos de desempenho sob carga.
Ferramentas:
- Apache JMeter para testes de carga
- Lighthouse para performance de frontend
Exemplo de cenário de teste de performance:
- Simular 1000 usuários acessando a página inicial simultaneamente
- Verificar o tempo de resposta médio (deve ser < 2 segundos)
- Monitorar o uso de CPU e memória do servidor
6.5. Testes de segurança
Realizamos testes de segurança regularmente para identificar e corrigir vulnerabilidades.
Ferramentas e práticas:
- OWASP ZAP para testes de segurança automatizados
- Análise estática de código com SonarQube
- Testes de penetração manuais trimestrais
Exemplo de teste de segurança automatizado:
# Executar OWASP ZAP via linha de comando
zap-cli quick-scan --self-contained --start-options "-config api.disablekey=true" https://nossa-aplicacao.comBoas práticas adicionais:
-
TDD (Test-Driven Development): Encorajamos a prática de TDD, escrevendo testes antes da implementação.
-
Testes de regressão: Executar todos os testes antes de cada release para garantir que mudanças não quebraram funcionalidades existentes.
-
Mocks e Stubs: Utilizar mocks para isolar unidades de código em testes unitários.
-
Testes de API: Garantir que todas as endpoints da API estejam cobertas por testes.
-
Testes de UI: Incluir testes de interface do usuário para garantir a correta renderização e funcionamento dos componentes.
-
Continuous Testing: Integrar a execução de testes no pipeline de CI/CD.
Processo de revisão de testes:
- Os revisores de código devem verificar se os testes apropriados foram adicionados ou atualizados com cada PR.
- PRs não devem ser aprovados se não incluírem testes adequados.
- A cobertura de código deve ser revisada no Codecov antes da aprovação do PR.
- Para funcionalidades significativas, os testes E2E no EndTest devem ser revisados e aprovados.
Lembre-se: Testes não são apenas uma etapa no processo de desenvolvimento, mas uma parte integral do nosso compromisso com a qualidade. Cada desenvolvedor é responsável por garantir que seu código seja adequadamente testado em todos os níveis antes de solicitar uma revisão.