Estou trabalhando em um aplicativo que possui várias camadas. Camada de acesso a dados para recuperar e salvar dados da fonte de dados, lógica de negócios para manipular dados, interface do usuário para mostrar os dados na tela.
Também estou fazendo testes de unidade da camada de lógica de negócios. O único requisito é testar o fluxo da lógica da camada de negócios. Então, eu uso a estrutura Moq para simular a camada de acesso a dados e testar a camada de lógica de negócios com a unidade MS.
Estou usando a programação da interface para fazer o design desacoplar o máximo possível, para que o teste de unidade possa ser realizado. A camada de negócios chama a camada de acesso a dados através da interface.
Estou enfrentando um problema ao tentar testar um dos métodos de lógica de negócios. Esse método funciona e cria um objeto e o passa para a camada de acesso a dados. Quando estou tentando zombar desse método da camada de acesso a dados, ele não pode ser zombado com êxito.
Aqui estou tentando criar um código de demonstração para mostrar meu problema.
Modelo:
public class Employee
{
public string Name { get; set; }
}
Camada de acesso a dados:
public interface IDal
{
string GetMessage(Employee emp);
}
public class Dal : IDal
{
public string GetMessage(Employee emp)
{
// Doing some data source access work...
return string.Format("Hello {0}", emp.Name);
}
}
Camada de lógica de negócios:
public interface IBll
{
string GetMessage();
}
public class Bll : IBll
{
private readonly IDal _dal;
public Bll(IDal dal)
{
_dal = dal;
}
public string GetMessage()
{
// Object creating inside business logic method.
Employee emp = new Employee();
string msg = _dal.GetMessage(emp);
return msg;
}
}
Teste de unidade:
[TestMethod]
public void Is_GetMessage_Return_Proper_Result()
{
// Arrange.
Employee emp = new Employee; // New object.
Mock<IDal> mockDal = new Mock<IDal>();
mockDal.Setup(d => d.GetMessage(emp)).Returns("Hello " + emp.Name);
IBll bll = new Bll(mockDal.Object);
// Act.
// This will create another employee object inside the
// business logic method, which is different from the
// object which I have sent at the time of mocking.
string msg = bll.GetMessage();
// Assert.
Assert.AreEqual("Hello arnab", msg);
}
No caso de teste de unidade, no momento da zombaria, estou enviando um objeto Employee, mas ao invocar o método da lógica de negócios, ele cria um objeto Employee diferente dentro do método. É por isso que não posso zombar do objeto.
Nesse caso, como projetar para que eu possa resolver o problema?
fonte
Respostas:
Em vez de criar um
Employee
objeto diretamente usandonew
, sua classeBll
poderia usar umaEmployeeFactory
classe para isso, com um métodocreateInstance
que é injetado pelo construtor:O construtor deve levar o objeto de fábrica através de uma interface
IEmployeeFactory
, para que você possa substituir facilmente a fábrica "real" por uma fábrica simulada.A fábrica simulada pode fornecer ao teste qualquer tipo de
Employee
objeto que você precise (por exemplo,createInstance
sempre pode retornar o mesmo objeto):Agora, usar esse mock no seu teste deve fazer o truque.
fonte
Eu trataria isso como uma única unidade para testar.
Desde que você controle todas as entradas das quais o
Employee
objeto é criado, o fato de ele ser criado no objeto testado não deve importar. Você só precisa de um método mock para retornar o resultado esperado se o conteúdo do argumento corresponder à expectativa.Obviamente, isso significa que você precisa fornecer lógica personalizada para o método simulado. A lógica avançada geralmente não pode ser testada apenas com o tipo de simulação "for x return y".
De fato, você não deve fazer com que ele retorne objetos diferentes nos testes do que na produção, porque, se o fizesse, não estaria testando o código que deveria criá-lo. Mas esse código é parte integrante do código de produção e, portanto, também deve ser coberto pelo caso de teste.
fonte
Employee
objeto diferente nos testes, não testará o código que normalmente o cria. Então você não deve mudar isso.É uma falha de algumas ferramentas de teste; você sempre deve usar interfaces e tudo deve ser criado de uma maneira que permita trocar o objeto baseado em interface por outro.
No entanto, existem ferramentas melhores - use o Microsoft Fakes (chamado Moles) que permite trocar qualquer objeto, mesmo estático e global. É necessária uma abordagem de nível mais baixo para substituir objetos, para que você não precise usar interfaces em todos os lugares, mantendo a maneira de escrever testes com os quais está acostumado.
fonte