TL;DR: Se você quer testar sua classe por meio de teste de unidade, essa classe não deve conter código de infra estrutura (como acesso a banco de dados, e etc), e ela também deve receber toda outra informação ou dependência necessária por meio de construtores ou parâmetros de métodos — a classe nunca deve buscar a informação diretamente ou instanciar uma dependência. Dessa forma, ela será facilmente testável por meio de testes de unidade.

Regras de negócio, no fim, nada mais são do que um monte de ifs e fors juntos. Portanto, deveríamos ser capazes de sempre testá-las por meio de simples testes de unidade. No entanto, às vezes nós dificultamos isso.

Veja o código abaixo. Nele, o FiltroDeFatura pega a lista de todas as faturas que está no banco de dados, e passeia por elas, guardando as que tem valores menor que 2000.

O código é simples, mas pense que ele poderia ser um pouco mais complicado. Portanto, precisamos testá-lo. A questão é: como? Afinal, não conseguimos escrever um teste de unidade pra ela; afinal é impossível executar o método filtra() sem passar por um banco de dados.

Essa é um tipo de código bastante comum nas aplicações por aí. O desenvolvedor sabe que não pode sair misturando SQL no meio de regra de negócio, e corretamente, coloca isso dentro do DAO. No entanto, ele instancia o DAO diretamente na classe, fazendo com que não seja possível executar a regra de negócio, sem passar pelo banco de dados.

E passar pelo banco de dados, na maioria das vezes, não é boa ideia. Escrever o teste é mais difícil (afinal, precisamos fazer INSERT dos dados no começo, DELETE depois, garantir o schema do banco, e etc), e mais demorado. E, aliás, não deveríamos precisar do banco de dados, para testar a simples regra de filtro de fatura.

A solução pra isso é mais fácil do que parece. Se você tem uma classe que contém regras de negócio, essa classe deve apenas conter regras de negócio. Ou seja, ifs e fors. Se sua regra de negócio precisar de alguma informação que venha de uma outra classe qualquer (seja um DAO, seja outra coisa), ela nunca deve “buscar” essa informação, mas sim “recebê-la”.

Ou seja, nesse código em particular, ou passamos a _List_ para o método _filtra(), _ou passamos o _FaturaDao_ pelo construtor. Veja:

Dessa forma, com o DAO sendo recebido pelo construtor da classe, conseguimos simular seu comportamento durante o teste, por meio de mock objects. E agora sim, nada de depender do banco para fazer um teste tão simples.

Portanto, guarde essa regra: se sua classe é uma classe que contém regras de negócio, ela nunca pode buscar as informações ou dependências que precisa por conta própria; ela deve sempre recebê-las.

Ah, essa ideia tem um nome bonito, inclusive: chama-se inversão de controle. Ou seja, “invertemos” a maneira tradicional de programar, que é sempre buscar pela dependência. Agora, alguém nos dá a dependência. Você pode ler mais sobre isso no meu livro de orientação a objetos e SOLID.