1
resposta

Teste no Controller

Eu fiz esse teste pro campo "texto", pois ele precisa ser obrigatório. Então eu testei os casos q daria o erro de campo obrigatório:

 describe("campos obrigatórios", () => {
        test.each([
            ["vazio", ""],
            ["undefined", undefined],
            ["null", null]
        ])("Deve lançar erro quando texto for %s", (_, valor) => {
            const executar = () => golombService.encode(valor, 2);

            expect(executar).toThrow(ErroValidacao);
            expect(executar).toThrow(MENSAGENS_ERRO.CAMPO_OBRIGATORIO("texto"));
        });

No teste do controller eu fiz assim testando só um valor q vai dar o erro de campo obrigatório. Eu devo testar os outros também ou seria uma repetição desnecessária?:

 describe("campos obrigatórios", () => {
        test("Deve chamar next quando texto for obrigatório", () => {
            req.body.texto = undefined;

            const erro = new ErroValidacao(MENSAGENS_ERRO.CAMPO_OBRIGATORIO("texto"));

            golombService.encode.mockImplementation(() => {
                throw erro;
            });

            golombController.encode(req, res, next);

            expect(golombService.encode).toHaveBeenCalledWith(undefined, 4);
            expect(next).toHaveBeenCalledWith(erro);
            expect(res.status).not.toHaveBeenCalled();
            expect(res.json).not.toHaveBeenCalled();
        });

Meu código no controller:

const encode = (req, res, next) => {
    try {
        const { texto, k } = req.body;

        const resultado = golombService.encode(texto, k);

        return res.status(200).json({ resultado });
    } catch (erro) {
        next(erro);
    }
};

Meu código no service:

const encode = (texto, k) => {
    golombValidation.validarEncodeGolomb(texto, k);

    const comprimido = [];
    const stopBit = "1";

    for(let i = 0; i < texto.length; i++){
        const charCode = texto.charCodeAt(i);

        const tamanhoPrefixo = Math.floor(charCode / k);
        const resto = charCode % k;
        const tamanhoSufixo = Math.ceil(Math.log2(k));

        const prefixo = "0".repeat(tamanhoPrefixo);
        const sufixo = resto.toString(2).padStart(tamanhoSufixo, "0");

        const codeword = prefixo + stopBit + sufixo;

        comprimido.push(codeword);
    }

    return comprimido;
}
1 resposta

Olá, Luidi. Como vai?

Essa é uma excelente dúvida sobre boas práticas de testes unitários. No contexto de Node.js e arquitetura em camadas, o objetivo é garantir que cada parte do código cumpra o seu papel sem necessariamente repetir a exaustão o que já foi testado em outra camada.

No seu caso, a lógica de o que é ou não um campo inválido já está coberta e garantida pelo teste do Service (onde você usou o test.each). No Controller, a responsabilidade é apenas garantir que, se o Service lançar um erro, o Controller saiba como capturá-lo e passá-lo adiante via next(erro).

Portanto, aqui estão algumas considerações:

  • Não é necessário repetir todos os casos: Testar apenas com um valor (como o undefined) no Controller já é suficiente para validar o fluxo de tratamento de exceção. Se o seu Controller consegue lidar com um ErroValidacao, ele lidará com todos os outros que o Service lançar.
  • Foco do teste: No Controller, você está testando a integração entre a requisição e a resposta. O teste atual já garante que o next é chamado e que a resposta não é enviada precocemente com res.status(200).
  • Dica de Manutenção: Se você repetir todos os casos (null, "", etc.) no Controller, toda vez que adicionar uma nova regra de validação no Service/Validation, terá que atualizar dois arquivos de teste diferentes, o que gera um trabalho extra desnecessário.

Uma pequena sugestão no seu teste de Controller: note que no expect você passou o valor 4 para o parâmetro k, mas no código do teste você não definiu esse valor em req.body. Garanta que os dados de entrada correspondam ao que o mock espera para evitar falsos negativos.

Espero que possa ter lhe ajudado!