Seguindo com o projeto baseado no TDD, vamos continuar os testes restantes e finalizar a implementação das regras de negócio na camada de domínio.
Até aqui testamos apenas as especificações da entidade Aluno que eram: Ter idade entre 6 e 18 anos e CPF único na base.
Utilizamos Rhino Mock onde criamos um repositório falso simulando uma consulta de CPF existente e Specification Pattern com o pacote DomainValidation. Talvez não houvesse necessidade aplicar specification pattern para um projeto pequeno. A ideia é apenas mostrar como podemos implementá-lo para atender n regras de negócio de forma simples.
Vamos agora validar as entidades Curso e Matricula. Para ambos, iremos utilizar a técnica de Mock para simular um retorno do banco de dados.
Curso deve possuir código único e uma matrícula não pode conter o mesmo aluno para o mesmo curso.
Passo 19 - Na pasta \Interfaces\Repository\ - crie duas interfaces - ICursoRepository e IMatriculaRepository. Estas interfaces irão herdar de IRepository e implementar métodos específicos.
ICursoRepository.cs
1 2 3 4 | public interface ICursoRepository : IRepository { Curso ObterPorCodigoCurso(string codigo); } |
IMatriculaRepository.cs
1 2 3 4 | public interface IMatriculaRepository : IRepository { Matricula ObterMatriculaAlunoCurso(Guid aluno, Guid curso); } |
Passo 20 - Na pasta \Specifications\Cursos - crie a classe CursoUnicoSpecification.cs. Crie também a classe MatriculaUnicaSpecification.cs na pasta \Specifications\Matriculas
CursoUnicoSpecification.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class CursoUnicoSpecification : ISpecification { private readonly ICursoRepository _cursoRepository; public CursoUnicoSpecification(ICursoRepository cursoRepository) { _cursoRepository = cursoRepository; } public bool IsSatisfiedBy(Curso curso) { return _cursoRepository.ObterPorCodigoCurso(curso.CodigoCurso) == null; } } |
A classe acima retornará null quando não encontrar o Código do curso na base. O processo é o mesmo do CPF.
MatriculaUnicaSpecification.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class MatriculaUnicaSpecification : ISpecification { private readonly IMatriculaRepository _matriculaRepository; public MatriculaUnicaSpecification(IMatriculaRepository matriculaRepository) { _matriculaRepository = matriculaRepository; } public bool IsSatisfiedBy(Matricula matricula) { return _matriculaRepository.ObterMatriculaAlunoCurso(matricula.AlunoId, matricula.CursoId) == null; } } |
A diferença na classe acima é que estamos passando o Guid de Aluno e Curso como parâmetro.
Passo 21 - Basta criar as classes que retornam a coleção de erros com base nas especificações de cada entidade. No nosso projeto, temos poucas especificações para Curso e Matricula, mas poderíamos ter n especificações para cada entidade.
Criar as classes - \Validations\Cursos\CursoCadastroValidation.cs e \Validations\Matriculas\MatriculaCadastroValidation.cs
CursoCadastroValidation.cs
1 2 3 4 5 6 7 8 | public class CursoCadastroValidation : Validator { public CursoCadastroValidation(ICursoRepository cursoRepository) { var cursoUnico = new CursoUnicoSpecification(cursoRepository); base.Add("cursoUnicoRule", new Rule(cursoUnico, "Código de curso já está cadastrado!")); } } |
MatriculaCadastroValidation.cs
1 2 3 4 5 6 7 8 | public class MatriculaCadastroValidation : Validator { public MatriculaCadastroValidation (IMatriculaRepository matriculaRepository) { var matriculaUnica = new MatriculaUnicaSpecification(matriculaRepository); base.Add("matriculaUnicaRule", new Rule(matriculaUnica, "Aluno já possui matrícula para esse curso!")); } } |
Nas classes acima, Herdamos a classe Validator do pacote DomainValidation, passamos a classe desejada(Aluno ou Curso), e injetamos dependência do reposítório no construtor. Instanciamos a especificação que desejamos validar, MatriculaUnicaSpecification, e a Rule retornará a mensagem de erro caso a spec não seja atendida.
Dá pra validar de outra forma? Sim uai!!! Coloca um monte de if e vamo que vamo... Lembrando, o uso do specification pattern é apenas sugestivo. Particularmente eu gostei bastante dessa abordagem, pois facilita bastante quando precisamos criar dezenas de regras.
Passo 22 - No projeto de teste crie as classes MatriculaCadastroTest.cs e CursoCadastroTest.cs na pasta \Validation\
CursoCadastroTest.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | [TestClass] public class CursoCadastroTest { public Curso Curso { get; set; } [TestMethod] public void Curso_Validation_True() { Curso = new Curso() { CodigoCurso = "2EF2016" }; var stubRepository = MockRepository.GenerateStub(); stubRepository.Stub(s => s.ObterPorCodigoCurso(Curso.CodigoCurso)).Return(null); // curso não encontrado - null var cursoValidation = new CursoCadastroValidation(stubRepository); Assert.IsTrue(cursoValidation.Validate(Curso).IsValid); } [TestMethod] public void Curso_Validation_False() { Curso = new Curso() { CodigoCurso = "2EF2016" }; var stubRepository = MockRepository.GenerateStub(); stubRepository.Stub(s => s.ObterPorCodigoCurso(Curso.CodigoCurso)).Return(Curso); // curso encontrado var cursoValidation = new CursoCadastroValidation(stubRepository); Assert.IsFalse(cursoValidation.Validate(Curso).IsValid); } } |
MatriculaCadastroTest.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | [TestClass] public class MatriculaCadastroTest { public Matricula Matricula { get; set; } [TestMethod] public void Matricula_Validation_True() { Matricula = new Matricula() { AlunoId = new Guid("b2c7e6da-4086-4bf3-9c2f-225852da34c3"), CursoId = new Guid("b7b6c5a1-2cea-4ee2-9967-b34d4f76ece6") }; var stubRepository = MockRepository.GenerateStub(); stubRepository.Stub(s => s.ObterMatriculaAlunoCurso(Matricula.AlunoId, Matricula.CursoId)).Return(null); var matriculaValidation = new MatriculaCadastroValidation(stubRepository); Assert.IsTrue(matriculaValidation.Validate(Matricula).IsValid); } [TestMethod] public void Matricula_Validation_False() { Matricula = new Matricula() { AlunoId = new Guid("b2c7e6da-4086-4bf3-9c2f-225852da34c3"), CursoId = new Guid("b7b6c5a1-2cea-4ee2-9967-b34d4f76ece6") }; var stubRepository = MockRepository.GenerateStub(); stubRepository.Stub(s => s.ObterMatriculaAlunoCurso(Matricula.AlunoId, Matricula.CursoId)).Return(Matricula); var matriculaValidation = new MatriculaCadastroValidation(stubRepository); Assert.IsFalse(matriculaValidation.Validate(Matricula).IsValid); } } |
Caso queira entender melhor as classes acima, na parte 2 desse tutorial temos a explicação baseada nos testes da entidade Aluno. O escopo é o mesmo.
Executando todos os testes nesse momento, teremos o resultado na imagem abaixo:
Resumo dos testes realizados até aqui:
Aluno_Consistente_False - faz a validação do CPF e da Idade digitados pelo usuário simulando dados inválidos.
Aluno_Consistente_True - faz o mesmo, simulando dados válidos.
Percebam que nesses dois métodos, fizemos uma primeira validação apenas com os dados informados.
Já nas próximas classes precisamos simular uma consulta no banco para validação antes de cadastrar na base, fazendo uso do falso repositório com Rhino Mock.
Aluno_Validation_False - Simula CPF existente na base retornando o próprio objeto que foi instanciado.
Aluno_Validation_True - Simula CPF inexistente com retornou null na consulta.
Os testes de Curso e Matricula seguem o mesmo escopo desses dois últimos.
Esse tutorial vai ficar maior do que eu imaginava. Estou disponibilizando o código fonte gerado até aqui no Github
Precisamos ainda finalizar as regras de negócio da Matrícula que serão validadas nas classes de serviço do domínio. E só para nos situarmos, vejam na imagem em qual camada estamos trabalhando dentro da arquitetura proposta pelo DDD.
A validação das regras de uma matrícula por faixa etária, conforme proposto nesse tutorial, será feita nas classes de serviços do domínio. Vamos trabalhar nelas no próximo post.
Código Fonte EscolaTDD - Parte 3 / GitHub
Vou deixar aqui novamente a referência desse projeto que está baseado nos padrões DDD, TDD, SOLID e Specification pattern.
Tutorial - Asp.Net DDD - Eduardo Pires
Tutorial SOLID - Eduardo Pires
Até mais!
I like reading through a post that will make people think. Also, thank you for permitting me to comment. https://www.omgab.com
The monthly preference of French sunseekers may seem a mere curiosity to the rest of the world, but for those who live there, it's a serious matter -- and one that annually grinds the entire nation to a standstill.
카지노사이트
https://www.bbdd66.com/super 슈퍼카지노
https://www.omgka.com/super 슈퍼카지노
https://www.dnfl4949.com/ 우리카지노사이트
https://www.dnfl4949.com/f1casino f1카지노
https://www.dnfl4949.com/33casino 33카지노
https://www.dnfl4949.com/corea 코리아카지노
https://www.dnfl4949.com/gatsby 개츠비카지노
https://www.dnfl4949.com/yescasino 예스카지노
https://www.ekffo150.com 우리카지노사이트