Capítulo 15: Engenharia de Software: Ciclo de Vida, Testes Automatizados e Padrões GoF
Capítulo 15: Engenharia de Software: Ciclo de Vida, Testes Automatizados e Padrões GoF
Módulo 01: Fundamentos da Computação • Ciência da Computação Formal
🗺️ 1. Pirâmide de Testes e Design de Software
flowchart TD
subgraph PIRAMIDE["Pirâmide de Qualidade de Software"]
E2E["Testes Ponta a Ponta (E2E / UI)
(Poucos, Lentos, Alto Custo de Manutenção)"]
INT["Testes de Integração
(Comunicação entre Módulos, Banco e APIs)"]
UNIT["Testes Unitários Automatizados (TDD)
(Milhares, Rápidos, Isolados, Baixo Custo)"]
E2E --- INT
INT --- UNIT
end
style UNIT fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
style INT fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style E2E fill:#ffebee,stroke:#f44336,stroke-width:2px
🏛️ 2. Fundamentação Teórica
A Engenharia de Software aplica abordagens sistemáticas, disciplinadas e quantificáveis ao desenvolvimento, operação e manutenção de sistemas complexos.
2.1 Modelos de Processo de Software
| Modelo | Dinâmica de Ciclo | Vantagens | Desvantagens | Quando Utilizar |
|---|---|---|---|---|
| Cascata (Waterfall) | Linear e sequencial (Requisitos $\to$ Design $\to$ Impl $\to$ Testes) | Rigor documental, marcos bem definidos | Inflexível a mudanças; atraso na entrega de valor | Projetos críticos regulados (aeroespacial, médico) |
| Espiral (Boehm) | Iterativo com análise formal de riscos a cada ciclo | Gestão precoce e rigorosa de riscos técnicos | Custo elevado de planejamento e especialistas | Sistemas corporativos de grande porte |
| Ágil (Scrum/XP) | Ciclos curtos (Sprints de 1-4 semanas) com feedback contínuo | Alta adaptabilidade a mudanças de escopo | Risco de perda de visão arquitetural global | Startups, SaaS e produtos digitais modernos |
2.2 Catálogo de Padrões de Projeto (GoF - Gang of Four)
Os 23 padrões clássicos dividem-se em três macrocategorias:
- Padrões Criacionais (Como objetos são instanciados):
- Factory Method: Define interface para criar objetos, delegando às subclasses a decisão da classe concreta.
- Singleton: Garante que uma classe possua apenas uma única instância em todo o ciclo de vida da aplicação.
- Builder: Separa a construção de um objeto complexo da sua representação final.
- Padrões Estruturais (Como classes e objetos são compostos):
- Adapter: Converte a interface de uma classe na interface esperada pelo cliente.
- Decorator: Agrega comportamentos adicionais a um objeto dinamicamente sem alterar sua estrutura.
- Facade: Provê uma interface simplificada e unificada para um subsistema complexo.
- Padrões Comportamentais (Como classes distribuem responsabilidades e algoritmos):
- Strategy: Permite definir uma família de algoritmos e alterná-los em tempo de execução.
- Observer: Notifica automaticamente múltiplos observadores quando um objeto sofre mutação de estado.
- Command: Encapsula uma requisição como um objeto, permitindo parametrização e operações de desfazer/refazer (undo/redo).
2.3 Disciplina TDD e Tipologias de Testes
O Test-Driven Development (TDD) inverte o fluxo tradicional através do ciclo:
- RED: Escrever um teste unitário automatizado que falha antes de qualquer linha de código de produção.
- GREEN: Escrever o código mínimo e estritamente necessário para fazer o teste passar.
- REFACTOR: Limpar o design, remover duplicações e otimizar mantendo a suíte de testes 100% verde.
💻 3. Implementação do Padrão Strategy com Teste Automatizado em Python
from abc import ABC, abstractmethod
from typing import List
# 1. Padrão GoF Strategy
class EstrategiaDesconto(ABC):
@abstractmethod
def calcular(self, valor: float) -> float:
pass
class DescontoEstudante(EstrategiaDesconto):
def calcular(self, valor: float) -> float:
return valor * 0.50
class DescontoBlackFriday(EstrategiaDesconto):
def calcular(self, valor: float) -> float:
return valor * 0.70
class Carrinho:
def __init__(self, estrategia: EstrategiaDesconto):
self._estrategia = estrategia
self._itens: List[float] = []
def adicionar(self, preco: float):
self._itens.append(preco)
def total(self) -> float:
subtotal = sum(self._itens)
return self._estrategia.calcular(subtotal)
# 2. Mini Suíte de Teste Automatizado (Princípio TDD)
def testar_regras_carrinho():
carrinho_estudante = Carrinho(DescontoEstudante())
carrinho_estudante.adicionar(100.0)
carrinho_estudante.adicionar(100.0)
assert carrinho_estudante.total() == 100.0, "Erro: Estudante deveria pagar 50%!"
carrinho_bf = Carrinho(DescontoBlackFriday())
carrinho_bf.adicionar(100.0)
assert carrinho_bf.total() == 70.0, "Erro: Black Friday deveria cobrar 70%!"
print("Todas as asserções de teste unitário PASSARAM com sucesso!")
if __name__ == "__main__":
print("=== ENGENHARIA DE SOFTWARE: STRATEGY & TESTES ===")
testar_regras_carrinho()