No TDD devo escrever primeiro o teste ou a interface primeiro?

23

Estou aprendendo TDD usando c #, tanto quanto sei que o teste deve impulsionar o desenvolvimento , ou seja, primeiro escreva um teste com falha depois de escrever o código mínimo para passar no teste e refatorar.

Mas também é dito que " Programa para Interface, não Implementação ", então escreva uma interface primeiro . É aqui que começa a minha confusão: se estou escrevendo a Interface primeiro, está violando duas coisas

  1. O código que é escrito para a interface não é conduzido pelo teste .

  2. Não é o mínimo, obviamente, eu posso escrever com uma classe simples.

Devo começar escrevendo testes para a interface também? sem nenhuma implementação, o que vou testar?

Se esta pergunta parece bobagem, desculpe-me por isso, mas estou totalmente confuso. Pode ser que eu esteja levando as coisas muito literalmente.

k4vin
fonte
8
"Programar em uma interface" significa separar o que você precisa de um pedaço de código da maneira como ele é feito. Não significa literalmente usar um interfacepara tudo. A classtambém fornece uma interface, porque você pode ocultar os detalhes da implementação em privatevariáveis.
Doval
@ Doval, Sim, você não precisa de uma interface para tudo, apenas o que é chamado de contract. Isso pode estar na forma de uma classe abstrata, por exemplo, embora não deva ser uma classe / método virtual porque você não pode instanciar.
trysis
2
O TDD diz: "escreva um teste que falhe". Alguns TDDers rígidos dizem que isso conta como "falha" se você não puder compilar o teste porque o tipo de dados no qual ele opera ainda não foi declarado.
Solomon Slow

Respostas:

29

Sua primeira violação ("O código escrito para a interface não é conduzido pelo teste.") Não é válido. Vamos usar um exemplo trivial. Suponha que você esteja escrevendo uma aula de calculadora e escrevendo uma operação de adição. Que teste você pode escrever?

public class CalculatorTest {
    @Test
    public void testAddTwoIntegers() {
        Calculator calc = new Calculator();
        int result = calc.add(2, 2)
        Assert.assertEquals(4, result);
    }
}

Seu teste acabou de definir a interface. É o addmétodo, vê? addrecebe dois argumentos e retorna sua soma. Posteriormente, você pode determinar que precisa de várias calculadoras e extrair uma interface Java (nesse caso) naquele momento. Seus testes não devem mudar, pois você testou a interface pública dessa classe.

Em um nível mais teórico, os testes são a especificação executável de um sistema. As interfaces para um sistema devem ser conduzidas pelos usuários desse sistema, e os testes são o primeiro método que você precisa para definir interações.

Não acho que você possa separar o design da interface do design de teste. Definir interações e projetar testes para elas é a mesma operação mental - quando envio essas informações para uma interface, espero um certo resultado. Quando algo está errado com a minha entrada, espero esse erro. Você pode fazer esse trabalho de design em papel e depois escrever seus testes a partir disso, ou pode fazê-los ao mesmo tempo - isso realmente não importa.

Michael K
fonte
2
+1 " Eu não acho que você pode separar o design da interface do design do teste " deve estar em negrito, IMHO :) #
Worrier binário
É ainda mais fácil mostrar, se você deseja testar mais de uma implementação de uma funcionalidade, diz uma Importação XML e uma Importação CSV, você pode testá-las exatamente com o mesmo método na mesma interface, embora a implementação seja alterada. Além disso, os testes envolvem muitas vezes zombarias e, para essa interface, são necessários.
Walfrat 21/03
Você diz que o teste não precisa mudar, mas new Calculator()a implementação está correta? Se for necessária uma nova implementação, talvez você faça um MultiplicationCalculator e precise alterar o teste para new AdditionCalculator()que ele ainda passe? Ou eu estou esquecendo de alguma coisa ?
Steve Chamaillard
3
@SteveChamaillard Claro, se o seu design alterar o nome da classe de Calculator para AdditionCalculator, o teste precisaria ser alterado para corresponder. Obviamente, ao fazer TDD, o que realmente aconteceria é que você alterasse o teste primeiro, e a mudança de classe seguiria para que o teste passasse.
Eric King
5

O que estamos fazendo quando escrevemos um interface? Estamos escrevendo código ou estamos criando?

Não sou fã da noção de Design Orientado a Testes, mas adoro o Desenvolvimento Orientado a Testes . Pessoalmente, obtive meus melhores resultados ao projetar a classe com antecedência, projetando a interface antes de escrever um teste. Não conto a interface como código. A interface é um design que implementarei usando TDD. É provável que mude e evolua conforme eu trabalho, mas é o meu roteiro (junto com a minha lista de testes).

Vou parar antes de começar a reclamar, mas espero que seja uma maneira útil de você pensar sobre isso.

Pato de borracha
fonte
4

No TDD devo escrever primeiro o teste ou a interface primeiro?

Tudo depende de quão ortodoxo / religioso você deseja fazer TDD .

Estou aprendendo TDD

Como você está aprendendo, experimente obter um fluxo de trabalho pessoal, que funcione para você.

  1. Se você quiser fazer isso de acordo com os livros , escreva primeiro um teste, o que obviamente falhará, porque você está começando com nenhum código. Então você escreve algum código para fazer o teste passar. Se isso for feito, você poderá refatorar o código existente, pois você tem um teste que fornece algum tipo de rede de segurança para refatorações. Decidir usar uma interface é algum tipo de refatoração.

  2. Além do TDD ou não: A questão de usar uma interface ou não não é interessante em primeiro lugar. É claro que, se você tiver certeza, tem um comportamento diferente que deseja espalhar por vários objetos, faz sentido pensar em usar uma Interface: Por exemplo, se você tem algum tipo de saída para destinos diferentes, faz sentido implementá-la via uma interface Writer e possui classes diferentes para a saída ( FileWriter , Printer etc.). Embora seja comum dizer para escrever em uma interface , isso não significa: use uma interface para tudo . Às vezes, é um nível de indireção para muito. Btw. o mesmo vale para serviços. Mas esse é um tópico diferente.

  3. Por outro lado, você pode desenvolver testes conduzidos de outra maneira: crie seu código para testabilidade. O que significa que você escreve código, que é fácil de testar - embora você escreva os testes posteriormente . Não importa se você escreve testes antecipadamente ou depois, desde que faça testes de qualquer maneira.

Thomas Junk
fonte
5
Não posso concordar com o último ponto "Não importa se você escreve testes antes ou depois, desde que faça de qualquer maneira". Se você escrever o teste posteriormente, não poderá ter certeza se o teste está testando a coisa certa.
K4vin
4
Como eu disse ... Depende de como ortodoxa você é ...
Thomas Junk
2

TDD ou BDD significaria primeiro fazer as interfaces de domínio e depois escrever testes contra eles pela minha interpretação. a implementação de uma interface tem um comportamento esperado.

ainda é teste antes do código, porque uma interface não contém lógica testável; é a estrutura na qual você escreve um teste.

Eu faria da seguinte maneira

  1. Escreva o comportamento semi-formal (dado: quando: então :)

  2. Escreva a interface (para hospedar o método de encapsulamento de comportamento)

  3. Escreva o teste que ele identifica (insira o dado, chame o quando, teste o então)

  4. Escreva / altere o concreto (classe que implementa a interface) para passar no teste

user3721330
fonte
0

Nunca escreva testes antes de projetar as interfaces. Ao pensar em quais tipos de testes escrever (design de teste), você também não deve simultaneamente projetar (arquitetar) seu aplicativo. Não pense em duas coisas ao mesmo tempo. Você já ouviu falar de separação de preocupações? Isso se aplica não apenas à estrutura física do seu código, mas também ao seu processo de pensamento.

Decida como seu aplicativo deve ser projetado primeiro. Isso significa que você projeta suas interfaces e os relacionamentos entre essas interfaces. Até que você tenha feito isso, não deve começar a pensar em testes. Depois de saber quais são suas interfaces, você pode primeiro criá-las e, em seguida, escrever testes contra elas ou escrever testes primeiro e depois criá-las. Neste último caso, obviamente, você não poderá compilar os testes. Não vejo nenhum dano nem qualquer violação da filosofia TDD na criação das interfaces antes dos testes.

Nissim Levy
fonte
o raciocínio na resposta principal parece mais atraente: "Não acho que você possa separar o design da interface do design de teste. Definir interações e projetar testes para eles são a mesma operação mental - quando envio essas informações para uma interface, espero um certo resultado . Quando algo está errado com a minha entrada, espero que este erro ... "#
2113
@gnat Eu acredito que Nissam aqui está se referindo à interfacepalavra-chave C # , não ao termo geral "interface".
precisa
@RubberDuck Também acho que sim e acredito que essa é uma abordagem ruim. "Até que você tenha feito isso, você não deve começar a pensar sobre os testes ..." Como eu escrevi, o raciocínio no topo Resposta aparência mais atraente, tanto no sentido geral de interface e no sentido da palavra-chave de concreto
mosquito
É justo o @gnat que não ficou claro em seu comentário. Pessoalmente, eu concordo com Nissam aqui. Acho que impede as pessoas de usar o TDD como uma desculpa para não projetar nada. YMMV.
precisa
-2

Não há problema em escrever a interface / código / teste ao mesmo tempo, desde que a incorporação ao projeto seja atômica.

A menos que seu chefe seja religioso sobre TDD, nesse caso, você provavelmente precisará escrever uma interface vazia -> teste -> código mínimo (etapa inútil) -> mais testes -> mais código inútil -> mais testes -> finalmente, escrever o código real - > pronto.

alternativo
fonte