Testar métodos do repositório apenas em testes de integração

87 views
Skip to first unread message

Riderman Sousa

unread,
Jun 11, 2013, 8:10:57 AM6/11/13
to dotnetar...@googlegroups.com

Esta dúvida é originada de outro post aqui mesmo no .Net Architects. Resolvi criar outra thread com foco apenas nesta questão.

Publiquei também no meu twitter sobre como/onde testar métodos do repositório.


Vamos a seguinte situação: Eu tenho uma interface IRepository como esta:


public interface IRepository<T>
    where T: class, IEntity
{
    IQueryable<T> Query(Expression<Func<T, bool>> expression);
    // ... Omitido
}

E uma implementação genérica do meu IRepository


public class Repository<T> : IRepository<T>
    where T : class, IEntity
{
    public IQueryable<T> Query(Expression<Func<T, bool>> expression)
    {
        return All().Where(expression).AsQueryable();
    }
}

Esta é uma implementação base e pode ser usada por qualquer repositório. Ela contém a implementação básica do meu ORM.

Alguns repositórios tem filtros específicos, neste caso teremos o IEmployeeRepository com um filtro específico:


public interface IEmployeeRepository : IRepository<Employee>
{
    IQueryable<Employee> GetInactiveEmployees();
}

E a implementação da interface IEmployeeRepository:


public class EmployeeRepository : Repository<Employee>, IEmployeeRepository // TODO: I have a dependency with ORM  at this point in Repository<Employee>. How to solve? How to test the GetInactiveEmployees method
{
    public IQueryable<Employee> GetInactiveEmployees()
    {
        return Query(p => p.Status != StatusEmployeeEnum.Active || p.StartDate < DateTime.Now);
    }
}

Dúvidas

  1. É corretor herdar de Repository<Employee>?
    O objetivo é reaproveitar código uma vez que toda a implementação de IRepository já foi feita. Se EmployeeRepositoryherdar apenas de IEmployeeRepository, terei de literalmente copiar e colar o código de Repository<T>.

  2. Neste nosso exemplo, em EmployeeRepository : Repository<Employee> o nosso Repository se encontra em nossa camada ORM. Ou seja, temos uma dependência aqui com o nosso ORM impossibilitando de realizar algum teste unitário.

  3. Como criar um teste unitário para garantir que o filtro GetInactiveEmployees retorne todos os Employees em que o Status != Active e StartDate < Data atual. Não posso criar um Fake/Mock de IEmployeeRepository porque o que eu estaria testando? Preciso testar a implementação real de GetInactiveEmployees.

O código completo encontra-se no Github



Riderman de Sousa Barbosa

Web Developer | MCPD Certify

Skype.: 4042-6002 | Cel.: (31) 8681-1986

bindsolution.com

Microsoft Parner Network

edmilson hora

unread,
Jun 11, 2013, 8:42:47 AM6/11/13
to dotnetar...@googlegroups.com
Oi Riderman,
neste caso testar a implementação real do repositório não é mais teste unitário passa a ser teste integrado.

O teste unitário, neste caso, testaria  se o repositório esta sendo chamado corretamente e então haveria uma implementação fake  ou mock para responder se ele foi chamado.

Para verificar, se  sua logica de filtro esta correta (teste unitário), eu só penso em um jeito, dados fake numa classe local,  onde a logica fosse aplicada, para ver se retorna foi o esperado.



De: Riderman Sousa <rider...@bindsolution.com>
Para: dotnetar...@googlegroups.com
Enviadas: Terça-feira, 11 de Junho de 2013 9:10
Assunto: [dotnetarchitects] Testar métodos do repositório apenas em testes de integração

--
Você recebeu esta mensagem porque faz parte do grupo .Net Architects hospedado no Google Groups.
Para postar envie uma mensagem para dotnetar...@googlegroups.com
Para sair do grupo envie uma mensagem para dotnetarchitec...@googlegroups.com
Para mais opções visite o grupo em http://groups.google.com/group/dotnetarchitects?hl=pt-br
---
Você está recebendo esta mensagem porque se inscreveu no grupo ".Net Architects" dos Grupos do Google.
Para cancelar a inscrição neste grupo e parar de receber seus e-mails, envie um e-mail para dotnetarchitec...@googlegroups.com.
Para obter mais opções, acesse https://groups.google.com/groups/opt_out.
 
 


Riderman Sousa

unread,
Jun 11, 2013, 9:25:00 AM6/11/13
to dotnetar...@googlegroups.com
Olá Edmilson.

Preciso testar se o filtro está retornando o resultado correto, neste caso, qualquer teste de IXRepository seria um teste de integração?
Qualquer ação no repositório `EmployeeRepository` seria um teste de integração. Por exemplo: `EmployeeRepository.Store(obj)` irá persistir o objeto no banco de dados e não em uma `IList` ou  `IDictionary`.




2013/6/11 edmilson hora <edmils...@yahoo.com.br>

Riderman Sousa

unread,
Jun 11, 2013, 9:31:16 AM6/11/13
to dotnetar...@googlegroups.com

Edmilson, esqueci de comentar mas não tenho como chamar EmployeeRepository.Store(obj) porque no meu projeto de testes unitários não existe uma referência ao ORM.

S
tore fica em no repositório genérico Repository<T> com uma referência ao NHibernate.



2013/6/11 Riderman Sousa <rider...@bindsolution.com>

Juan Lopes

unread,
Jun 11, 2013, 11:13:42 AM6/11/13
to dotnetar...@googlegroups.com
Eu arranjaria uma forma de injetar a factory do queryable inicial (no
seu caso o método All()) para testar somente a implementação de
GetInactiveEmployees.

Explicando melhor: o que você precisa, na verdade é testar se o
predicado definido em GetInactiveEmployees faz sentido com o seu
negócio (se ele vai ser traduzido para uma query válida no seu banco é
outro teste). Por isso, se você puder capturar as operações em cima do
seu queryable, você poder repetí-las, digamos, usando um
List<Employee> e ver se isso faz sentido.

Uma forma fácil de fazer isso é injetar o IQueryable<Employee> que
representa o All no construtor do repositório. IQueryables são
imutáveis por contrato, então basta você ter uma instância. No teste
você pode simplesmente injetar um mock Queryable que só captura as
chamadas a ele. Tem um exemplo (incompleto) no meu github [1], que
mostra o menor IQueryable possível (com seu respectivo
IQueryProvider).

[1] https://github.com/juanplopes/simple-commons/blob/master/src/Simple/Expressions/EmptyQueryable.cs


--
https://github.com/juanplopes

Riderman Sousa

unread,
Jun 11, 2013, 12:22:22 PM6/11/13
to dotnetar...@googlegroups.com
Olá Juan.

Não tenho como repetir as operações utilizadas no meu método `GetInactiveEmployees` porque estas operações não estão disponíveis em meu projeto de testes unitários.
Por exemplo, `All` (método que retorna IQueryable de Employees) está na classe base `Repository<T>` que se encontra na camada do ORM. O método `All` nem mesmo é exibido pelo compilador/interlisense.

Sobre injetar IQueryable, se eu entendi (me corrija se estiver errado) você está sugerindo que crie um mock `Mock<EmployeeRepository>` e injetar no construtor o IQueryable de All correto?
Então, nem mesmo criar um mock de `Mock<EmployeeRepository>` eu consigo. O compilador já acusa erro pedindo para adicionar a referência ao NHibernate.





2013/6/11 Juan Lopes <m...@juanlopes.net>

edmilson hora

unread,
Jun 11, 2013, 5:27:46 PM6/11/13
to dotnetar...@googlegroups.com
Isso, qualquer operação que envolva o ORM real e/ou banco real é um teste integrado.


Enviadas: Terça-feira, 11 de Junho de 2013 10:25
Assunto: Re: [dotnetarchitects] Testar métodos do repositório apenas em testes de integração

Juan Lopes

unread,
Jun 12, 2013, 4:26:57 PM6/12/13
to dotnetar...@googlegroups.com
Estou vendo o código aqui. Para mim, o maior problema conceitual é
você tentar insinuar que existe qualquer tipo de independência entre o
contrato de um repositório (IRepository<Employee>), sua implementação
de acordo com o domínio (EmployeeRepository) e a implementação de
infra (Repository<Employee>). Todos eles estão fortemente acoplados
pela herança de EmployeeRepository.

Além do mais, esse seu repositório não é bem um repositório de
verdade. Ele parece muito com uma mistura entre um DAO (por essa
tentativa de modelar todas as operações necessárias para todas as
entidades) com um Specification (por retornar IQueryable<T> nas
consultas).

Esse problema de design é que faz com que seus testes sejam custosos.
E eles estão gritando justamente isso. Você não vai conseguir testar
isoladamente com esse acoplamento todo.

--
https://github.com/juanplopes

Francisco Berrocal

unread,
Jun 18, 2013, 11:53:12 AM6/18/13
to dotnetar...@googlegroups.com
Eu sei que é um pouco tarde, mas dá uma olhada neste artigo:


E também nos links no final dele, tem outros artigos relacionando testes com repositórios e isolação de banco de dados nos testes!
Talvez lhe ajude

Att, 
Francisco Hisashi Berrocal

Reply all
Reply to author
Forward
0 new messages