3
respostas

Mockando Contexto em Serviço e Repositório

//Classe
public class Carro{
    public int Codigo {get; set; }
    public string Descricao { get; set; }
}

//Contexto
public class MeuContexto
{
    public virtual DbSet<Carro> Carro { get; set; }
}

//Repositório
public class CarroRepositorio
{
    public CarroRepositorio(MeuContexto contexto) : base (contexto) { }

    public virtual int NovoCodigo()
    {
        return context.Carro.Max(c => c.Codigo) += 1; 
    }
}

//Serviço
public class CarroService
{
    CarroRepositorio repCarro;

    public CarroService(MeuContexto context) : base(context) 
    {
        repCarro = new CarroRepositorio(context)
    }

    public virtual Carro Buscar(int Id)
    {
        return repCarro.Listar().Where(model => model.Codigo == Id).FirstOrDefault();
    }
}

//Testes Com Repositorio que Funciona
[TestMethod]
public void RetornarProximaPlacaComRepositorio()
{
    var _Carros = new List<Carro>{
            new Carro() { Codigo = 1, Descricao = "Gol" },
            new Carro() { Codigo = 2, Descricao = "Uno" }
        }.AsQueryable();

    var DbSet = new Mock<DbSet<Carro>>();
    DbSet.As<IQueryable<Carro>>().Setup(m => m.Provider).Returns(_Carros.Provider);
    DbSet.As<IQueryable<Carro>>().Setup(m => m.Expression).Returns(_Carros.Expression);
    DbSet.As<IQueryable<Carro>>().Setup(m => m.ElementType).Returns(_Carros.ElementType);
    DbSet.As<IQueryable<Carro>>().Setup(m => m.GetEnumerator()).Returns(_Carros.GetEnumerator());

    var Contexto_Mocado = new Mock<MeuContexto>();
    var repositorio = new CarroRepositorio(Contexto_Mocado.Object);

    var ProximoCodigo = repositorio.NovoCodigo();
    var QuantidadeDeCarros = Contexto_Mocado.Object.Carro.ToList();

    Assert.AreEqual(2, QuantidadeDeCarros.Count());
    Assert.AreEqual(3, ProximoCodigo);
}

//Testes Com Serviço que não Funciona
[TestMethod]
public void BuscarCarroComServico()
{
     var Contexto_Mocado = new Mock<GesCooperContext>();
     var repositorio = new Mock<CarroRepositorio>(Contexto_Mocado);
     var servico = new Mock<CarroService>(repositorio.Object.context);

     var Retorno = servico.Object.Buscar(1);

     Assert.AreEqual("Gol", Retorno.FirstOrDefault);
}

Nesse momento queria que o serviço ficasse com o repositório mocado que funciona no primeiro teste e então buscar no mesmo contexto sem precisar setar o Setup para o serviço, conforme a seguir:

[  servico.Setup(s => s.Buscar(1)).Returns(new Carro { Codigo = 1, Descricao = "Gol"});  ]

Alguém sabe se é possível configurar alguma variável do Mock para este objetivo?

3 respostas

Oi Leomar, tudo bem? E se você criar um método só para retornar esse mock? Ou então declarar um campo no nível da classe. Assim você pode utilizá-lo várias vezes e deixar seus testes mais enxutos.

Então, para enxugar o código criei uma classe estática que me retorna os Mocks necessários. Quanto ao problema, solucionei criando um segundo construtor passando além do contexto, um repositório (mockado) que é configurado na minha classe estática, setando os valores retornados de acordo os valores retornados pelo repositório real. ( Obs. está funcionando como eu imaginava)

//Serviço
public class CarroService
{
    CarroRepositorio repCarro;

    public CarroService(MeuContexto context) : base(context) 
    {
        repCarro = new CarroRepositorio(context)
    }

    public CarroService(MeuContexto context, CarroRepositorio RepositorioMock) : base(context) 
    {
        repCarro = RepositorioMock;
    }

    public virtual Carro Buscar(int Id)
    {
        return repCarro.Listar().Where(model => model.Codigo == Id).FirstOrDefault();
    }
}

No entanto o problema agora é outro... Vamos lá: Digamos que a classe Carro tem uma Foreing Key de Proprietário, algo como:

//Classe
public class Carro{

    public int Codigo {get; set; }
    public string Descricao { get; set; }

    [Key, ForeignKey("Proprietario")]
    [Display(Name = "Proprietario")]
    //[Range(1, 9999999)]
    public int ProprietarioCodigo { get; set; }
    public Proprietario Proprietario { get; set; }
}

Acontece que ProprietarioCodigo vem com seu valor default, ou seja, Zero. Ao executar o teste com Mock para salvar o Carro não indica erro (proprietário não existente). Gostaria que validasse o campo, que é um Foreing Key sem a necessidade do DataAnnotation "[Range(1, 9999999)] = Maior que Zero".

No teste que efetivamente salva em banco de dados, ele me retorna esse erro, pois é uma validação do EntityFramework, existe alguma forma de tratar essa validação para que fique um mock o mais próximo possível de um banco de dados?

Acho que você pode fazer essa checagem ao final do teste:

.
.
.
            var codigos =
                carros.Select(c => c.ProprietarioCodigo)
                .ToList();

            CollectionAssert.DoesNotContain(codigos, 0);

O método CollectionAssert.DoesNotContain() irá falhar se algum código de proprietário for igual a zero.