Tenho três perguntas sobre como implementar uma camada de serviço. Para exemplificar vou utilizar a classe abaixo:
public class ProcessoService // Qual a necessidade de se ter uma interface para abstrair a camada de serviço?
{
private readonly Processo _processo; // É correto ter um objeto de domínio como dependência para um serviço?
private readonly IRepository<Processo> _repositorio;
private readonly IRepository<ProcessoTipoDocumento> _tipoDocumentoRepository;
private readonly IMappingEngine _mapperEngine;
public ProcessoService(Processo processo
, IRepository<Processo> repositorio
, IRepository<ProcessoTipoDocumento> tipoDocumentoRepository
, IMappingEngine mapperEngine)
{
_processo = processo;
_repositorio = repositorio;
_tipoDocumentoRepository = tipoDocumentoRepository;
_mapperEngine = mapperEngine;
}
public IQueryable GetTiposDocumentos(ProcessoDocumentoEntidadeEnum entidade) // Filtrar dados faz parte de um serviço?
{
// Filtro retornando uma query que é um .Concat entre os repositórios _repositorio e tipoDocumentoRepository (utiliza o objeto _processo)
}
}
As dúvidas estão bem comentadas, mas vamos aos detalhes:
Vejo em muitos artigos a utilização de uma interface para abstrair a camada de serviço.
Mas nunca entendi qual a real necessidade de abstrair isto, uma vez que as dependências são injetadas no construtor não terei nenhum problema com os testes!
Um serviço realiza operações em um objeto de domínio, correto? Então seria correto colocar como dependência via construtor este objeto de domínio?
Até onde vai um serviço? Por exemplo, filtrar dados em repositórios distintos, posso colocar na camada de serviço?
No exemplo acima meu serviço possui uma dependência a outro repositório, isto porque o filtro que é realizado faz uma busca em 2 repositórios distintos.
Antes que alguém diga "Coloque este filtro GetTiposDocumentos na interface IProcessoRepository e implemente ele na sua class ProcessoRepository : Repository<Processo>, IProcessoRepository"
Resposta: Repository<Processo> é a implementação concreta do repositório (neste caso NHibernate).
Se fizer isto, em meus testes, não poderei referenciar diretamente IProcessoRepository. Eu teria de criar um repositório fake para literalmente Copiar e Colar a implementação do GetTiposDocumentos.
Sei que algum ponto do meu design está falho, gostaria da ajuda de vocês para descobrir.
Web Developer | MCPD Certify
Skype.: 4042-6002 | Cel.: (31) 8681-1986
bindsolution.comMicrosoft Parner Network
Edmilson, então. O que ocorre é o seguinte:
A minha interface IProcessoRepository
é inútil. Na verdade qualquer implementação específica para um repositório como ProcessoRepository
:
IProcessoRepository é inútil
, simplesmente porque no meu projeto de testes tenho de testar a implementação. E não posso testar a implementação já que o Repositório depende do ORM.
Perguntei sobre a camada de serviço porque não sei se é o local correto para colocar filtros como GetTiposDocumentos
(anteriormente estava na implementação
ProcessoRepository
).

Riderman,a sua interface IProcessoRepository não é inútil pelo simples fato que você a usapara desacoplar suas classes. Se hoje você salva em um BD e amanhã quer salvarem um arquivo, como faz?
Simples, ao invés de implementar o repositório Orm.Nhibernate (por exemplo), crio uma nova class library e um repositório para .FileSystem.
IProcessoRepository não tem detalhes de persistência, apenas especificidades. Quem tem detalhes da persistência é o Repository<T> que está em outra camada.
E até onde eu saiba, você também precisa desacoplar o seu repositório para podertestar as suas outras classes. Por exemplo, se você quiser criar um Mock de umrepositório para testar a integração das suas classes com o repositório.
IProcessoRepository
IReposytory<T>.IProcessoRepository (ProcessoRepository) herda de
Reposytory<Processo>, IProcessoRepository (IReposytory<Processo> se quiser testar a integração com minhas classes e meu repositório.ProcessoRepository : Repository<Processo>, IProcessoRepository depende do IProcessoRepository porque preciso testar a implementação.
Simples, ao invés de implementar o repositório Orm.Nhibernate (por exemplo), crio uma nova class library e um repositório para.FileSystem.
IProcessoRepositorynão tem detalhes de persistência, apenas especificidades. Quem tem detalhes da persistência é oRepository<T>que está em outra camada.
a interfacecomoIProcessoRepositoryherda de.IReposytory<T>
A implementação deIProcessoRepository(ProcessoRepository) herda de(Reposytory<Processo>, IProcessoRepository`Repository<T>`repositório genérico. Encontra-se no projeto Orm.Nhinermate).
Não sei se entendi, mas posso criar mockIReposytory<Processo>se quiser testar a integração com minhas classes e meu repositório.
O IProcessoRepository contém apenas especificidades, filtros relacionados ao Processo neste caso. Se eu quiser testar estes filtros tenho de testar a implementação, e a implementaçãoProcessoRepository : Repository<Processo>, IProcessoRepositorydepende doORM. Não tenho nem como testar estes filtros nos testes de unitáriosjá que os mesmos não tem referência ao projeto ORM
Não faz sentido mocarIProcessoRepositoryporque preciso testar a implementação.
Tudo isso leva a conclusão de que ou você tem esta lógica específica (filtros etc..) na sua camada de serviço, assim você irá conseguir testar nos testes unitários pois ela não depende do ORM, ou qualquer testeIProcessoRepository será um teste de integração.Sei que parece confuso, criei um branch neste repositório para exemplificar:1. Meu repositório agora tem um filtro específico.2. A implementação deste filtro depende do ORM3. Preciso testar a implementação, mas não sei como.
Olá Riderman,
2013/6/7 Riderman Sousa <rider...@bindsolution.com>
Simples, ao invés de implementar o repositório Orm.Nhibernate (por exemplo), crio uma nova class library e um repositório para.FileSystem.
IProcessoRepositorynão tem detalhes de persistência, apenas especificidades. Quem tem detalhes da persistência é oRepository<T>que está em outra camada.Justamente. IProcessoRepository herda de Repository<T> e você cria uma classe queimplementa a interface IProcessoRepository. Na interface IProcessoRepository vocêcoloca as especificidades de persistência de um Processo. Se não há, esta interfacefica vazia mesmo. Mas se houver alguma no futuro, ela já está prontinha para vocêacrescentá-la e o impacto no seu sistema será mínimo.
a interfacecomoIProcessoRepositoryherda de.IReposytory<T>
A implementação deIProcessoRepository(ProcessoRepository) herda de(Reposytory<Processo>, IProcessoRepository`Repository<T>`repositório genérico. Encontra-se no projeto Orm.Nhinermate).Não, não. Você faz IProcessoRepository herdar deIRepository<T> e depois implementa*apenas* o IProcessoRepository na classeProcessoRepository. Pelo menos é assimque eu faço por aqui...
Se eu herdar
IProcessoRepository apenas deIRepository<T> terei de implementar toda a lógica do Repository<T> novamente.
Fica estranho esta abordagem. ProcessoRepository : IProcessoRepository.
Eu já tenho uma classe Repository<T> :
IRepository<T> com toda a implementação.IRepository<T>Não sei se entendi, mas posso criar mockIReposytory<Processo>se quiser testar a integração com minhas classes e meu repositório.
O IProcessoRepository contém apenas especificidades, filtros relacionados ao Processo neste caso. Se eu quiser testar estes filtros tenho de testar a implementação, e a implementaçãoProcessoRepository :depende doRepository<Processo>, IProcessoRepositoryORM. Não tenho nem como testar estes filtros nos testes de unitáriosjá que os mesmos não tem referência ao projeto ORM
Não faz sentido mocarIProcessoRepositoryporque preciso testar a implementação.E qual o problema de você criar umProcessoRepositorioMemoria que implementeIProcessoRepository e que guarde os dados em um Dictionary e lá você faça osfiltros e etc?Não estou vendo onde precisa do ORM para se fazer deste modo. Uma vez vocêmandou um link de um site, em que a pessoa fazia exatamente assim. Dá uma olhadalá de novo...
Se eu criar um
ProcessoRepositorioMemoria e la fizer a implementação, o que eu estaria testando?
Preciso testar a implementação real de
ProcessoRepositorio e não uma implementação que fiz na camada de testes.
Tudo isso leva a conclusão de que ou você tem esta lógica específica (filtros etc..) na sua camada de serviço, assim você irá conseguir testar nos testes unitários pois ela não depende do ORM, ou qualquer testeIProcessoRepository será um teste de integração.Sei que parece confuso, criei um branch neste repositório para exemplificar:1. Meu repositório agora tem um filtro específico.2. A implementação deste filtro depende do ORM3. Preciso testar a implementação, mas não sei como.Olha, meu conhecimento em .NET e principalmente Linq é meio parco, mas acreditoque dê para implementar sim estes filtros em objetos armazenados em um Dictionary,que estaria em um ProcessoRepositorioMemoria.
--[]'s
--fx