As I am not really experienced in unit testing, I am trying to gather some rules that I will learn first.
Tenha cuidado ao aprender "regras" para problemas que você nunca encontrou. Se você se deparar com alguma "regra" ou "melhor prática", sugiro encontrar um exemplo simples de brinquedo de onde essa regra é "suposta" para ser usada e tentar resolver o problema você mesmo , ignorando o que a "regra" diz.
Nesse caso, você pode tentar criar 2 ou 3 classes simples e alguns comportamentos que devem ser implementados. Implemente as classes da maneira que parecer natural e escreva um teste de unidade para cada comportamento. Faça uma lista de todos os problemas encontrados, por exemplo se você começou com as coisas trabalhando de uma maneira, então teve que voltar e mudar depois; se você ficou confuso sobre como as coisas deveriam se encaixar; se você ficou irritado ao escrever clichê; etc.
Em seguida, tente resolver o mesmo problema seguindo a regra. Mais uma vez, faça uma lista dos problemas encontrados. Compare as listas e pense em quais situações podem ser melhores ao seguir a regra e quais não podem.
Quanto à sua pergunta, eu costumo favorecer uma abordagem portos e adaptadores , onde fazemos uma distinção entre "lógica central" e "serviços" (isso é semelhante a distinguir entre funções puras e procedimentos eficazes).
A lógica do núcleo é toda sobre o cálculo de coisas "dentro" do aplicativo, com base no domínio do problema. Ele pode conter classes como User
, Document
, Order
, Invoice
, etc. Não há problema em ter classes principais chamando new
para outras classes principais, já que elas são detalhes de implementação "internos". Por exemplo, criar um Order
também pode criar um Invoice
e um Document
detalhando o que foi pedido. Não há necessidade de zombar destes durante os testes, porque estas são as coisas reais que queremos testar!
As portas e adaptadores são como a lógica do núcleo interage com o mundo exterior. É aqui que coisas como Database
, ConfigFile
, EmailSender
, etc. vivem. Estas são as coisas que tornam o teste difícil, por isso é aconselhável criar estas fora da lógica principal, e passá-las conforme necessário (com injeção de dependência, ou como argumentos de método, etc.).
Dessa forma, a lógica central (que é a parte específica do aplicativo, onde a lógica de negócios importante vive e está sujeita a maior rotatividade) pode ser testada por conta própria, sem precisar se preocupar com bancos de dados, arquivos, e-mails etc. Podemos apenas passar alguns valores de exemplo e verificar se obtemos os valores de saída corretos.
As portas e os adaptadores podem ser testados separadamente, usando simulações para o banco de dados, sistema de arquivos, etc., sem ter que se preocupar com a lógica de negócios. Podemos apenas passar alguns valores de exemplo e ter certeza de que eles estão sendo armazenados / lidos / enviados / etc. apropriadamente.