Pergunta

Por exemplo, isso artigo os apresenta.

Qual é o benefício?

A análise estática parece legal, mas ao mesmo tempo impediria a capacidade de passar nulo como um parâmetro no teste de unidade. (Se você seguiu o exemplo no artigo)

Enquanto está no tópico dos testes de unidade - dado como as coisas estão agora certamente não há sentido para contratos de código se você já praticar testes automatizados?

Atualizar

Tendo brincado com contratos de código, estou um pouco decepcionado. Por exemplo, com base no código na resposta aceita:

public double CalculateTotal(Order order)
{
    Contract.Requires(order != null);
    Contract.Ensures(Contract.Result<double>() >= 0);
    return 2.0;
}

Para testes de unidade, você ainda tem que escrever testes para garantir que o nulo não possa ser aprovado, e o resultado é maior ou igual a zero se os contratos forem logíca de negócios. Em outras palavras, se eu fosse remover o primeiro contrato, nenhum teste quebraria, a menos que eu tivesse especificamente um teste para esse recurso. Isso se baseia em não usar a análise estática incorporada nas edições melhores (Ultimate etc ...) do Visual Studio.

Essencialmente, todos se resumem a uma maneira alternativa de escrever declarações tradicionais. Minha experiência realmente usando TDD, com contratos de código mostra o porquê e como eu fiz isso.

Foi útil?

Solução

Não acho que testes de unidade e contratos interfiram muito entre si e, se alguma coisa contratar deve ajudar a testes de unidade, pois remove a necessidade de adicionar testes repetitivos tediosos para argumentos inválidos. Os contratos especificam o mínimo que você pode esperar da função, enquanto os testes de unidade tentam validar o comportamento real para um conjunto específico de entradas. Considere este exemplo artificial:


public class Order
{
    public IEnumerable Items { get; }
}

public class OrderCalculator
{
    public double CalculateTotal(Order order)
    {
        Contract.Requires(order != null);
        Contract.Ensures(Contract.Result<double>() >= 0);

        return 2.0;
    }
}

Claramente, o código satisfaz o contrato, mas você ainda precisará de testes de unidade para validá -lo realmente se comporta como você esperaria.

Outras dicas

Qual é o benefício?

Digamos que você queira ter certeza de que um método nunca retorna null. Agora, com os testes de unidade, você deve escrever vários casos de teste em que chama o método com entradas variadas e verificar se a saída não é nula. O problema é que você não pode testar todas as entradas possíveis.

Com contratos de código, você apenas declara que o método nunca retorna null. O analisador estático reclamará se não for possível provar isso. Se não reclamar, você sabe que sua afirmação está correta Para todas as entradas possíveis.

Menos trabalho, a correção perfeita garante. O que não gosta?

Os contratos permitem que você diga qual é o objetivo real do código, em vez de deixar o que o código faça com quaisquer argumentos aleatórios que sejam entregues como a definição do ponto de vista do compilador ou o próximo leitor do código. Isso permite uma análise estática significativamente melhor e otimização de código.

Por exemplo, se eu declarar um parâmetro inteiro (usando a notação do contrato) estar na faixa de 1 a 10, e tenho uma matriz local na minha função declarada do mesmo tamanho, que é indexada pelo parâmetro, o compilador pode dizer que não há possibilidade de erro de subscrito, produzindo um código melhor.

Você pode afirmar que o NULL é um valor válido em um contrato.

O objetivo do teste de unidade é verificar dinamicamente que o código alcança qualquer propósito declarado que tenha. Só porque você escreveu um contrato para uma função, não significa que o código faça isso ou que a análise estática pode verificar se o código faz isso. Os testes de unidade não desaparecem.

Bem, ele não interferirá no teste da unidade em geral. Mas como eu vi você mencionou algo sobre TDD.

Se eu pensar sobre isso nessa perspectiva, acho que poderia/pode alterar o procedimento do padrão

  • Criar método (apenas assinatura)
  • Criar teste de unidade -> Implementar o teste
  • Execute o teste: deixe falhar
  • Implementar o método, hackear -o até o fim apenas para fazê -lo funcionar
  • Execute o teste: veja o passe
  • refatorar seu corpo (possivelmente confuso)
  • (reencontre o teste apenas para ver que você não quebrou nada)

Este seria o procedimento de teste de unidade muito difícil de complosas. Nesse contexto, acho que você pode inserir contratos de código entre o 1º e o 2º ponto como

  • Criar método (apenas assinatura)
  • Insira contratos de código para os parâmetros de entrada de métodos
  • Criar teste de unidade -> Implementar o teste
  • ...

A vantagem que vejo no momento é que você pode escrever testes de unidade mais fáceis, no sentido de que não precisariam verificar todos os caminhos possíveis, pois alguns já são levados em consideração por seus contratos definidos. Ele apenas oferece verificação adicional, mas não substituiria os testes de unidade, pois sempre haverá mais lógica no código, mais caminho que deve ser testado com testes de unidade como de costume.

Editar

Outra possibilidade que eu não considerei antes seria adicionar os contratos de código na parte de refatoração. Basicamente, como uma maneira adicional de garantir as coisas. Mas isso seria de alguma forma redundante e como as pessoas não gostam de fazer coisas redundantes ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top