Posted By

delm on 11/02/10


Tagged

unit-test memento


Versions (?)

Como provar una implementación de Memento.


 / Published in: C#
 

URL: http://failfast.chileagil.cl/questions/como-probar-una-implementacion-de-memento

Tengo una implementación legada de un patrón memento para una clase bastante grande, unas 15 propiedades de las cuales 5 de ellas corresponden a clases con sus propias propiedades adicionales.

Este memento está implementado de manera que un presentador tiene en memoria un objeto del mismo tipo que el modelo con el único propósito de mantener el estado previo, el que luego es restaurado si se necesita hacer un rollback de la edición. El traspaso del estado de un objeto a otro se hace propiedad a propiedad (mediante reflection)

Para hacer una refactorización, necesito generar una cobertura de pruebas unitarias decente para asegurar que el funcionamiento de la aplicación no se vea alterado por las mejoras que se introducirán.

Lo complejo, es que me encuentro haciendo pruebas unitarias muy redundantes, probando propiedad por propiedad que sea restablecido su valor al cancelar la edición.

La otra alternativa que tengo, es hacer un conjunto de asserts en un solo test para probar todas las propiedades de una sola vez, pero es tedioso y una conocida mala práctica de pruebas unitarias.

Ninguno de estos approach me deja convencido, ya que al agregar una propiedad en la clase bajo pruebas (que es posible que suceda) los test la van a dejar fuera de cobertura sin alertarme.

¿Se les ocurre alguna forma de mejorar la situación?

  1. public class Comuna {
  2. public int ComnunaId{get;set;}
  3. public string Nombre {get;set;}
  4. }
  5.  
  6. public class Direccion {
  7. public int DireccionId{get;set;}
  8. public string Calle {get;set;}
  9. public string Numeracion {get;set;}
  10. public Comuna Comuna{ get;set;}
  11. }
  12.  
  13. public class Persona : IPersona {
  14. public int PersonaId {get;set;}
  15. public string Nombre { get; set;}
  16. public string Apellido {get;set;}
  17. public Direccion Direccion {get;set;}
  18. }
  19.  
  20. public interface IViewPersona: IPersona {
  21. IComando ComandoAceptar {get;set;}
  22. IComando ComandoCancelar {get;set;}
  23. IList<Comuna> Comunas {get;set;}
  24. }
  25. public class PresentadorPersona {
  26.  
  27. private IPersona memento;
  28. private IViewPersona view;
  29. private IRepositorio repo;
  30.  
  31. public PresentadorPersona(IPersona persona, IViewPersona view, IRepositorio repo) {
  32. this.view = view;
  33. this.repo = repo;
  34.  
  35. TraspasaValores(persona,this.view);
  36.  
  37. memento = new Persona();
  38. TraspasaValores(persona,memento);
  39.  
  40. EnlazaComandos();
  41. }
  42.  
  43. //Este es un codigo ilustrativo, en la aplicación lo realiza una librería externa
  44. private void TraspasaValores(IPersona origen, IPersona destino) {
  45. destino.PersonaId = origen.PersonaID;
  46. destino.Nombre = origen.Nombre;
  47. destino.Apellido = origen.Apellido;
  48. destino.Direccion.DireccionId = origen.Direccion.DireccionID;
  49. destino.Direccion.Calle = origen.Direccion.Calle;
  50. destino.Direccion.Numeracion = origen.Direccion.Numeracion;
  51. destino.Direccion.Comuna.ComnunaId = origen.Direccion.Comuna.ComnunaId;
  52. destino.Direccion.Comuna.Nombre = origen.Direccion.Comuna.Nombre;
  53. }
  54.  
  55.  
  56. public void EnlazaComanodos() {
  57. //Executed es un evento en la interfaz IComando
  58. // += es un operador de registro a evento.
  59. view.ComandoAceptar.Executed += ComandoAceptar;
  60. view.ComandoCancelar.Executed += ComandoCancelar;
  61. }
  62.  
  63. public void ComandoAceptar(){
  64.  
  65. //tomo es estado de la vista
  66. IPersona modelo = new Persona();
  67. TraspasaValores(view,modelo);
  68.  
  69. if(ModeloEsValido(modelo){
  70. repo.Guarda(mdoelo);
  71. // establezco el estado anterior como válido
  72. TraspasaValores(view,memento);
  73. }
  74. }
  75.  
  76. public void ComandoCancelar() {
  77.  
  78. // establezco el valor de la vista en el memento
  79. TraspasaValores(memento,view);
  80. }
  81. }
  82.  
  83. public class TestPresentadorPersona() {
  84.  
  85.  
  86. public void ComandoCancelar_AlEjecutarce_DebeReestablecerValoresAVista() {
  87. IPersona persona = CreaPersonaInicial();
  88. IPersona estadoInicial = CreaPersonaInicial();
  89. IViewPersona viewMock = MockRepository.CreateMock<IViewPersona>();
  90. IRepository repoMock = MockRepository.CreateMock<IRepository>();
  91. PresentadorPersona presentador = new PresentadorPersona(persona, viewMock,repoMock);
  92.  
  93. ModificaEstadoPersona(persona);
  94.  
  95. presentador.ComandoCancelar();
  96.  
  97. Assert.That(persona.PersonaId,Is.EqualTo(estadoInicial.PersonaId));
  98. Assert.That(persona.Nombre,Is.EqualTo(estadoInicial.Nombre));
  99. Assert.That(persona.Apellido,Is.EqualTo(estadoInicial.Apellido));
  100. Assert.That(persona.Direccion.DireccionId,Is.EqualTo(estadoInicial.Direccion.DireccionId));
  101. Assert.That(persona.Direccion.Calle,Is.EqualTo(estadoInicial.Direccion.Calle));
  102. Assert.That(persona.Direccion.Numeracion,Is.EqualTo(estadoInicial.Direccion.Numeracion));
  103. Assert.That(persona.Comuna.ComunaId,Is.EqualTo(estadoInicial.Comuna.ComunaId));
  104. Assert.That(persona.Comuna.Nombre,Is.EqualTo(estadoInicial.Comuna.Nombre));
  105. }
  106.  
  107. public IPersona CreaPersonaInicial(){
  108. IPersona persona = new Persona();
  109. persona.PersonaId = 1;
  110. persona.Nombre = "test nombre";
  111. persona.Apellido = "test apellido";
  112. persona.Direccion = new Direccion();
  113. persona.Direccion.DireccionId = 1;
  114. persona.Direccion.Calle = "test calle";
  115. persona.Direccion.Numeracion = "34A test";
  116. persona.Comuna = new Comuna();
  117. persona.Comuna.ComunaId = 1;
  118. persona.Comuna.Nombre = "test comuna";
  119. return persona;
  120. }
  121.  
  122. public void ModificaEstadoPersona(IPersona persona){
  123. persona.PersonaId = 2;
  124. persona.Nombre = "test nombre modificado";
  125. persona.Apellido = "test apellido modificado";
  126. persona.Direccion = new Direccion();
  127. persona.Direccion.DireccionId = 2;
  128. persona.Direccion.Calle = "test calle modificado";
  129. persona.Direccion.Numeracion = "34A test modificado";
  130. persona.Comuna = new Comuna();
  131. persona.Comuna.ComunaId = 2;
  132. persona.Comuna.Nombre = "test comuna modificado";
  133. }
  134.  
  135. //Este es un codigo ilustrativo, en la aplicación lo realiza una librería externa
  136. private void TraspasaValores(IPersona origen, IPersona destino) {
  137. destino.PersonaId = origen.PersonaID;
  138. destino.Nombre = origen.Nombre;
  139. destino.Apellido = origen.Apellido;
  140. destino.Direccion.DireccionId = origen.Direccion.DireccionID;
  141. destino.Direccion.Calle = origen.Direccion.Calle;
  142. destino.Direccion.Numeracion = origen.Direccion.Numeracion;
  143. destino.Direccion.Comuna.ComnunaId = origen.Direccion.Comuna.ComnunaId;
  144. destino.Direccion.Comuna.Nombre = origen.Direccion.Comuna.Nombre;
  145. }
  146. }

Report this snippet  

You need to login to post a comment.