Testar projetos SharePoint algumas vezes pode ser um desafio, principalmente por causa dos dados estarem armazenados no SharePoint e para executar os testes eles devem ser executados diretamente de dentro do servidor.
Para esse tipo de problema existem uma solução que consiste em substituir a camada de acesso a dados, no caso fazer um mock, e testar as regras de negócio sem precisar do SharePoint.
Neste post vou mostrar um exemplo de como fazer um mock utilizando a biblioteca Moq com o padrão repostitório para executar os testes unitários nas regras de negócio.
Entidade
Neste case vamos fazer algo bem simples, onde existirá uma entidade chamada pessoa, algumas propriedades e um método de negócio, que é bem simples e só concatena as propriedades, a listagem 01 mostra o código da classe Pessoa.
public class Pessoa
{
public int ID { get; set; }
public string Nome { get; set; }
public DateTime DataNascimento { get; set; }
public string Endereco { get; set; }
public int Idade
{
get
{
return (int) DateTime.Now.Subtract(DataNascimento).TotalDays / 365;
}
}
public string ConcatenarDadosUsuario()
{
return string.Format(“ID: {0}, Nome: {1}, Idade: {2}, Endereço: {3}”, this.ID.ToString(), this.Nome, this.Idade.ToString(), this.Endereco);
}
}
Listagem 01: Implementação da classe pessoa
Repositório
Utilizando o padrão repositório todos os métodos de acesso a dados ficam na classe repositório, facilidando a sua substituição na hora do teste. O primeiro passo é construir a interface, conforme a listagem 02, depois implementar a classe que irá acessar o SharePoint para trabalhar com os dados. Por não haver necessidade, a classe que implementa a interface do repositório não foi implementada, apenas criadas com os métodos padrão. Em um ambiente real ela precisa ser implementada e é a partir dela que todo o acesso ao SharePoint é feito.
public interface IRepositorioPessoas
{
Pessoa ObterPorID(int pessoaID);
List<Pessoa> ObterTodos();
List<Pessoa> ObterPorFiltro(string nome);
Pessoa Salvar(Pessoa pessoa);
bool Excluir(int ID);
}
Listagem 02: A interface seguindo padrão repositório
public class RepositorioPessoa: IRepositorioPessoas
{
public Pessoa ObterPorID(int pessoaID)
{
throw new NotImplementedException();
}
public List<Pessoa> ObterTodos()
{
throw new NotImplementedException();
}
public List<Pessoa> ObterPorFiltro(string nome)
{
throw new NotImplementedException();
}
public Pessoa Salvar(Pessoa pessoa)
{
throw new NotImplementedException();
}
public bool Excluir(int ID)
{
throw new NotImplementedException();
}
}
Listagem 03: Classe que trabalhar com os dados do SharePoint e implementa a inteface da listagem 02
Teste
A classe de teste é uma classe de teste unitário do Visual Studio, além da implementação feita na listagem 03 é necessário por a referência no projeto a biblioteca Moq (using Moq), que pode ser baixada diretamente pelo Visual Studio através do NuGet Packages (ou pelo site do Moq).
A implementação da classe de teste é um pouco diferente de um testes normal, a primeira coisa a ser feita, na criação da classe de teste é criar o objeto moq para simular a nossa classe de negócio. Todos os dados e regras dos métodos serão implementados neste momento, veja o construtor PessoaTeste, onde um repositório de dados é montado e os métodos implementados. Vejam que é implementação do método mesmo, com as regras sobre os dados recém criados.
A partir do momento que todas as interações com os dados estão feitas, os testes podem ser criados e executados. Como as regras de negócio ficam em outra camada, é simples obter os dados fake e passar para eles e depois obter o resultado, possibilitando assim o teste das regras mesmo sem ter o repositório de dados oficial, no caso o SharePoint.
[TestClass]
public class PessoaTest
{
public readonly IRepositorioPessoas MockRepositorioPessoa;
public PessoaTest()
{
List<Pessoa> pessoas = new List<Pessoa>
{
new Pessoa {ID = 1, Nome = “Pedro de Lara”, Endereco = “Rua Sem Nome, Nr 1″, DataNascimento = new DateTime(1990, 01, 01)},
new Pessoa {ID = 2, Nome = “Carlos Lara da Silva”, Endereco = “Rua Sem Nome, Nr 2″, DataNascimento = new DateTime(1980, 12, 23)},
new Pessoa {ID = 3, Nome = “João Cunha”, Endereco = “Rua Sem Nome, Nr 3″, DataNascimento = new DateTime(1989, 02, 02)
}
};
// Criação do Mock utilizando Moq
Mock<IRepositorioPessoas> mockProductRepository = new Mock<IRepositorioPessoas>();
// Nas linhas abaixo os métodos estão sendo configurados no mock
// Retorna todas as pessoas
mockProductRepository.Setup(mr => mr.ObterTodos()).Returns(pessoas);
// Retorna a pessoa pelo ID
mockProductRepository.Setup(mr => mr.ObterPorID(
It.IsAny<int>())).Returns((int i) => pessoas.Where(
p => p.ID == i).Single());
// Retorna as pessoas pelo filtro do nome
mockProductRepository.Setup(mr => mr.ObterPorFiltro(
It.IsAny<string>())).Returns((string i) => pessoas.Where(
p => p.Nome.Contains(i)).ToList());
// Exclui a pessoa com ID passado por parâmetro
mockProductRepository.Setup(mr => mr.Excluir(It.IsAny<int>())).Returns(
(int id) =>
{
Pessoa pessoa = pessoas.Where(p => p.ID == id).Single();
pessoas.Remove(pessoa);
return true;
});
// Salva (insere ou altera) uma pessoa
mockProductRepository.Setup(mr => mr.Salvar(It.IsAny<Pessoa>())).Returns(
(Pessoa pessoa) =>
{
DateTime now = DateTime.Now;
if (pessoa.ID.Equals(default(int)))
{
// Insere a pessoa nova
pessoa.ID = pessoas.Count() + 1;
pessoas.Add(pessoa);
return pessoa;
}
else
{
// Atualiza a pessoa existente
var original = pessoas.Where(
q => q.ID == pessoa.ID).Single();
if (original == null)
{
return null;
}
original.Nome = pessoa.Nome;
original.Endereco = pessoa.Endereco;
original.DataNascimento = pessoa.DataNascimento;
return original;
}
});
// Finaliza a configuração do mock
this.MockRepositorioPessoa = mockProductRepository.Object;
}
/// <summary>
/// Verifica se todos as pessoas foram retornadas
/// </summary>
[TestMethod]
public void PodeRetornarTodasPessoas()
{
// Obtém todas as pessoas
IList<Pessoa> pessoas = this.MockRepositorioPessoa.ObterTodos();
Assert.IsNotNull(pessoas); // Teste se é nulo
Assert.AreEqual(3, pessoas.Count); // Verifica o número de pessoas retornadas
}
/// <summary>
/// Verifica se todos se a pessoa foi retornada a partir do ID
/// </summary>
[TestMethod]
public void PodeRetornarPessoaPorID()
{
// Obtém a pessoa com ID 1
Pessoa pessoa = this.MockRepositorioPessoa.ObterPorID(1);
Assert.IsNotNull(pessoa); // Teste se é nulo
Assert.AreEqual(1, pessoa.ID); // Verifica a pessoa retornada é a correta
}
/// <summary>
/// Verifica se todos as pessoas foram retornadas pelo filtro
/// </summary>
[TestMethod]
public void PodeRetornarObterPorFiltro()
{
string nome = “Lara”;
// Obtém a pessoa com ID 1
List<Pessoa> pessoas = this.MockRepositorioPessoa.ObterPorFiltro(nome);
Assert.IsNotNull(pessoas); // Teste se é nulo
Assert.AreEqual(2, pessoas.Count); // Verifica a pessoa retornada é a correta
Assert.AreEqual(true, pessoas[0].Nome.Contains(nome)); // Verifica a pessoa retornada é a correta
Assert.AreEqual(true, pessoas[1].Nome.Contains(nome)); // Verifica a pessoa retornada é a correta
}
/// <summary>
/// Verifica se a pessoa pode ser inserida
/// </summary>
[TestMethod]
public void PodeInserir()
{
Pessoa pessoa = new Pessoa();
pessoa.Nome = “Pessoa da Silva”;
pessoa.Endereco = “Rua com Nome 123, nr 12, CEP 34032-000″;
pessoa.DataNascimento = new DateTime(1979, 12, 21);
int contador = this.MockRepositorioPessoa.ObterTodos().Count;
// Salva a pessoa
pessoa = this.MockRepositorioPessoa.Salvar(pessoa);
Assert.IsNotNull(pessoa); // Teste se é nulo
Assert.AreEqual(pessoa.ID, contador + 1);
}
/// <summary>
/// Verifica se a pessoa pode ser alterada
/// </summary>
[TestMethod]
public void PodeAlterar()
{
Pessoa pessoa = new Pessoa();
int id = 1;
pessoa.ID = id;
string nome = “Pessoa da Silva”;
pessoa.Nome = nome;
pessoa.Endereco = “Rua com Nome 123, nr 12, CEP 34032-000″;
pessoa.DataNascimento = new DateTime(1979, 12, 21);
int contador = this.MockRepositorioPessoa.ObterTodos().Count;
// Salva a pessoa
pessoa = this.MockRepositorioPessoa.Salvar(pessoa);
Assert.IsNotNull(pessoa); // Teste se é nulo
Assert.AreEqual(pessoa.ID, id);
Assert.AreEqual(pessoa.Nome, nome);
}
/// <summary>
/// Verifica se todos as pessoas foram retornadas
/// </summary>
[TestMethod]
public void PodeExcluir()
{
int id = 3;
// Obtém a pessoa com ID 1
bool excluido = this.MockRepositorioPessoa.Excluir(id);
Assert.AreEqual(true, excluido);
}
/// <summary>
/// Verifica se todos as pessoas foram retornadas
/// </summary>
[TestMethod]
public void PodeConcacentarDadosUsuario()
{
Pessoa pessoa = this.MockRepositorioPessoa.ObterPorID(2);
string dadosUsuario = pessoa.ConcatenarDadosUsuario();
string dadosUsuarioCalculado = string.Format(“ID: {0}, Nome: {1}, Idade: {2}, Endereço: {3}”, pessoa.ID.ToString(), pessoa.Nome, pessoa.Idade.ToString(), pessoa.Endereco);
Assert.AreEqual(dadosUsuario, dadosUsuarioCalculado);
}
}
Listagem 03: Implementação do teste unitário
O código-fonte está disponível no GitHub: Testes-Unitarios-SharePoint
15/04/2012 às 11:00
Muito bom. Obrigado
15/04/2012 às 11:01
Muito Bom. Tks