Na vida de todo desenvolvedor, chega um momento em que ele pensa em criar um componente de teste para sua ideia. Vou melhorar - na vida de todo bom desenvolvedor. Quando você é júnior e não assume nenhuma responsabilidade especial, tem direito a muitos erros e pode corrigi-los a qualquer momento. Você não é responsável pelo produto criado e não tem motivação para gastar um minuto extra para verificar novamente o código gerado. “Nada, esse batente não pode ser reproduzido”, “isso parece funcionar”, “bem, pelo menos, faz o que precisa ser” - se você quiser superar o nível do berçário do programador, terá que negar cada um desses pensamentos.
Com o desenvolvimento de sua própria experiência de programação, você tem novos e mais legais e grandes clientes. Você ficará encantado com alguns (de todos, se tiver sorte) - as pessoas são boas e pagam generosamente e não são exigentes quanto aos problemas que surgem. Vejamos um caso simples (muito simples, mas a principal coisa por trás disso) de criar um manipulador de formulários a partir de um programador que não conhece o incômodo.
Então, a tarefa simples chegou - escrever um manipulador de formulários. O objetivo é aceitar solicitações de clientes para a compra de tijolos. O cliente é grande, ele está envolvido em grandes entregas de tijolos a granel (por exemplo, para uma quantidade superior a 500.000 rublos - para sentir pelo menos algum nível de responsabilidade pelo que está acontecendo). A concorrência é acirrada - os clientes podem ir rapidamente ao fornecedor de tijolos se não responderem dentro de um dia.
Foi dito ao nosso programador que é necessário salvar os dados do cliente a partir do formulário - o nome do representante, número de telefone, nome da empresa do cliente, volume do pedido e um campo opcional de descrição do pedido. No cérebro de Porakinin, um formulário simples foi criado rapidamente com campos padrão para a frente do site:

Os dados do formulário são enviados por uma solicitação AJAX, sem recarregar a página. Além disso, o programador assume o design do manipulador de formulários e precisa lidar com uma tarefa bastante trivial - adicionar entradas para o novo cliente à tabela de pedidos já existente e enviar ao cliente um e-mail com uma notificação sobre o novo cliente.

O formulário funciona, os dados são salvos com sucesso, o cliente está satisfeito. Mas, de repente, uma ligação irritada é recebida pelo cliente: "assim, eles dizem que o pedido chegou - a empresa milionária quer comprar todos os tijolos de mim, mas o número de telefone não veio do formulário e como posso contatá-los agora?! Amanhã encontrarão outro fornecedor! Como assim o que você fez ?! A culpa é sua ... " O cliente rasga e joga, menos nervos, menos confiança e menos respeito. A situação é extremamente padrão para um júnior - a ausência de qualquer validação e teste dos dados recebidos do formulário. A primeira tarefa (validação) é resolvida extremamente simplesmente adicionando regras de validação:

A partir de agora, o cliente do site indicará apenas os dados corretos necessários para o processamento posterior. No mesmo estágio, o desenvolvedor tem a idéia de testar o código para evitar ainda mais uma situação tão embaraçosa. Por exemplo, testar o campo de sobrenome terá esta aparência (para simplificar o exemplo básico, a proteção csrf está desativada):

Sabemos que, na ausência desse campo, o código deve retornar uma resposta com um erro e um status de 400 prescritos por nós. Esses métodos de teste são prescritos para cada situação específica (ou validação de campo específica, tudo depende das tarefas e da imaginação do desenvolvedor).
Mas existe um método de desenvolvimento diferente do que "eu fiz, mas agora vou verificar"? Primeiro escrevemos o código, tropeçamos nos batentes da execução, corrigimos e depois lembramos dos testes. Essa abordagem pode ir de sosla para nós e nossos clientes, considerando o cliente multimilionário perdido (embora teoricamente todos esses clientes ficariam). E então me perguntei - e se começarmos a lógica de criar o aplicativo pelo lado oposto - primeiro faremos exigências ao "executor" e depois faremos com que atenda a esses requisitos? Vamos tentar.
Deixamos a tarefa como antes, mudamos apenas a abordagem. Precisamos escrever um manipulador de formulários com os campos fio, telefone, corp, quant e conteúdo. O resultado da execução bem-sucedida é o status 200, adicionando um campo ao Pedido com a mensagem "ok" e retornando dados no registro inserido, outras opções - status 400 e uma lista de erros.
Primeiro, precisamos escrever um método de teste para preencher validamente os dados do formulário:

Em seguida, crie a rota e o método do controlador necessários (enquanto vazio). Se executarmos o teste agora, espera-se um erro. Validar dados válidos não é tudo o que precisamos. Agora começamos a testar a validação do campo do formulário. Determinamos quais campos são obrigatórios - fio, telefone, corp, quant e adicionamos um método para verificação (o comentário é opcional):

O manipulador de formulários simplesmente terá que verificar se há dados recebidos fio, telefone, corp, quant. Como removemos todos os campos obrigatórios da solicitação, um erro nos erros deve ser retornado para cada um deles. No caso de pelo menos um deles não estar presente - o problema de execução. Se desejar, você pode adicionar uma verificação de mensagem, como foi feito anteriormente (verifique “ok”).
Emitimos uma verificação do comprimento mínimo dos campos fio, telefone e corp (uma verificação semelhante será feita para o tamanho máximo e para caracteres inválidos nesses campos).

Nossas verificações estão em vigor, você pode executar e verificar

Perfeito. Nosso aplicativo falhou em 5 de 5 testes. Nosso objetivo adicional é passar por métodos de teste que definem valores inválidos para campos e formam regras de validação para os dados recebidos. A lógica é mais ou menos assim: o campo fio não pode estar vazio; Comprimento não inferior a 3 e não superior a 120; esta é uma sequência com o conjunto de caracteres permitido no nome (letras, hífens, recuos). O resultado dessa lógica em todos os campos:

Em resposta a um arquivo, uma lista de erros foi adicionada, erros que correspondem a cada campo "problema". Isso nos ajudará a verificar campos específicos para validação (assertJsonStructure no arquivo de teste). Em seguida, adicionamos o método de validação e obtemos a versão final:

E, finalmente, podemos verificar como nosso script funciona nos testes (lembro-me, houve 5 falhas em 5 testes).

Como você pode ver, todos os testes foram aprovados com êxito e apenas uma entrada foi inserida no banco de dados (pois apenas um método foi configurado para funcionar corretamente).

Quais são as descobertas? O desenvolvimento de aplicativos, começando com testes, é uma opção melhor do que a escrita usual de funcionalidade. A necessidade de receber do método apenas o necessário é comparável à disciplina do exército - o código faz exatamente o que você precisa dele, não um passo para o lado. No entanto, essa abordagem tem um lado negativo (embora controverso) - o fato é que escrever funcionalidades adicionais (que estão testando) também leva algum tempo alocado para o desenvolvimento do projeto. Quanto a mim, a escolha é clara - um bom programador deve escrever testes, e começar com a funcionalidade do teste ajuda a escrever um projeto confiável e que funcione bem. Vou tentar usá-lo em algo menos trivial.