Estoy trabajando en una aplicación que tiene varias capas. Capa de acceso a datos para recuperar y guardar datos de la fuente de datos, lógica de negocios para manipular datos, interfaz de usuario para mostrar los datos en pantalla.
También estoy haciendo pruebas unitarias de la capa de lógica de negocios. El único requisito es probar el flujo de la lógica de la capa empresarial. Así que uso el marco Moq para simular la capa de acceso a datos y probar la capa de lógica de negocios con la Unidad MS.
Estoy usando la programación de interfaz para hacer que el diseño se desacople tanto como sea posible para que se pueda hacer una prueba unitaria. Capa de acceso a datos de llamada de capa empresarial a través de la interfaz.
Tengo un problema cuando intento probar uno de los métodos de lógica de negocios. Ese método funciona y crea un objeto y lo pasa a la capa de acceso a datos. Cuando intento burlarme de ese método de capa de acceso a datos, entonces no puedo burlarme con éxito.
Aquí estoy tratando de crear un código de demostración para mostrar mi problema.
Modelo:
public class Employee
{
public string Name { get; set; }
}
Capa de acceso a datos:
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);
}
}
Capa lógica empresarial:
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;
}
}
Prueba de unidad:
[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);
}
En el caso de prueba unitaria en el momento de la burla, estoy enviando un objeto Empleado, pero cuando invoco el método de lógica de negocios, está creando un objeto Empleado diferente dentro del método. Por eso no puedo burlarme del objeto.
En ese caso, ¿cómo diseñar para que pueda resolver el problema?
fuente
Respuestas:
En lugar de crear un
Employee
objeto directamente mediante el usonew
, su claseBll
podría usar unaEmployeeFactory
clase para esto, con un métodocreateInstance
, que se inyecta a través del constructor:El constructor debe llevar el objeto de fábrica a través de una interfaz
IEmployeeFactory
, para que pueda reemplazar la fábrica "real" fácilmente por una fábrica simulada.La fábrica simulada puede proporcionarle a la prueba cualquier tipo de
Employee
objeto que necesite para su prueba (por ejemplo,createInstance
siempre podría devolver el mismo objeto):Ahora usar este simulacro en tu prueba debería ser el truco.
fuente
Lo trataría como una sola unidad para probar.
Siempre que controle todas las entradas a partir de las cuales
Employee
se crea el objeto, el hecho de que se cree en el objeto probado no debería importar. Solo necesita un método simulado para devolver el resultado esperado si el contenido del argumento coincide con las expectativas.Obviamente, significa que debe proporcionar una lógica personalizada para el método simulado. La lógica avanzada a menudo no se puede probar con solo simulacros "para x retorno y".
De hecho, usted debe no hacerlo volver objeto diferente en las pruebas de lo que será en la producción, ya que si lo hiciera, no estaría probando el código que debe crearlo. Pero ese código es parte integral del código de producción y, por lo tanto, también debe estar cubierto por el caso de prueba.
fuente
Employee
objetos en las pruebas, no probará el código que normalmente lo crea. Entonces no deberías cambiarlo.Es una falla de algunas herramientas de prueba, siempre debe usar interfaces y todo debe crearse de una manera que le permita intercambiar el objeto basado en la interfaz por otro.
Sin embargo, hay mejores herramientas: tome Microsoft Fakes (se llamaba Moles) que le permite intercambiar cualquier objeto, incluso los estáticos y globales. Se necesita un enfoque de nivel más bajo para reemplazar objetos, de modo que no tenga que usar interfaces en todas partes mientras mantiene la forma de escribir las pruebas a las que está acostumbrado.
fuente