En el anterior post, implementé la recuperación de los datos de un Tema de libros. No implementé aún ninguna vista. Estoy escribiendo los tests, e implementando el código del controlador. Es hora de agregar un nuevo Tema (Subject), usando una acción del controlador.
Este fue mi primer test:
[TestMethod] public void AddSubject() { IList<Subject> subjects = GetSubjects(); Subject subject = new Subject() { Name = "Chemistry" }; SubjectController controller = new SubjectController(subjects); ActionResult result = controller.Create(subject); Assert.IsNotNull(result); Assert.IsTrue(subjects.Any(s => s.Name == "Chemistry")); Assert.AreNotEqual(0, subject.Id); }GetSubjects() es un método ayudante que presenté en el anterior posts. Retorna una lista de temas para tests. Agregué una nueva acción en la clase controladora, para que la solución compile:
public ActionResult Create(Subject subject) { throw new NotImplementedException(); }Compiló, y el test quedó en rojo:
![]()
Entonces, completé el método de acción con el código mínimo para que pase el test:
public ActionResult Create(Subject subject) { subject.Id = this.subjects.Max(s => s.Id); subjects.Add(subject); return RedirectToAction("Index"); }Pero quiero redireccionar a la vista de detalle luego de haber dado de alta un item. Agrego el test:
RedirectToRouteResult redirect = (RedirectToRouteResult)result; Assert.IsTrue(string.IsNullOrEmpty(redirect.RouteName)); Assert.IsTrue(redirect.RouteValues.ContainsKey("id")); Assert.AreEqual(subject.Id, redirect.RouteValues["id"]); Assert.IsTrue(redirect.RouteValues.ContainsKey("action")); Assert.AreEqual("Details", redirect.RouteValues["action"]);Cambio el código de la acción para que cumpla con el nuevo requerimiento:
public ActionResult Create(Subject subject) { subject.Id = this.subjects.Max(s => s.Id); subjects.Add(subject); return RedirectToAction("Details", new { id = subject.Id }); }Ahora, el test en verde:
![]()
Seguí un camino similar para escribir el test de actualización de un Tema existente. Esta es la versión actual de ese test:
[TestMethod] public void UpdateSubject() { IList<Subject> subjects = GetSubjects(); Subject literature = subjects.Where(s => s.Name == "Literature").FirstOrDefault(); Subject subject = new Subject() { Name = "SciFi" }; SubjectController controller = new SubjectController(subjects); ActionResult result = controller.Update(literature.Id, subject); Assert.IsNotNull(result); Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult)); RedirectToRouteResult redirect = (RedirectToRouteResult)result; Assert.IsTrue(string.IsNullOrEmpty(redirect.RouteName)); Assert.IsTrue(redirect.RouteValues.ContainsKey("id")); Assert.AreEqual(literature.Id, redirect.RouteValues["id"]); Assert.IsTrue(redirect.RouteValues.ContainsKey("action")); Assert.AreEqual("Details", redirect.RouteValues["action"]); Assert.IsTrue(subjects.Any(s => s.Name == "SciFi")); Assert.AreEqual(literature.Id, subjects.Where(s => s.Name == "SciFi").Single().Id); }La acción del controlador:
public ActionResult Update(int id, Subject subject) { Subject toupdate = this.subjects.Where(s => s.Id == id).Single(); toupdate.Name = subject.Name; return RedirectToAction("Details", new { id = id }); }Todos los tests en verde:
![]()
Algunas advertencias: los tests están revisando dos salidas: los cambios en el dominio (por ahor auna simple lista) y los resultados de las acciones (un tema MVC). Debería hacer refactor (seguramente en un futuro post) de la implementación del controlador, para separar las actualizaciones del dominio de los resultados de la navegación. Escribí el ejemplo de esta manera para mostrar cómo hacer refactor más adelante para conseguir una mejor implementación. Mi idea es tener un servicio de manejo de temas, y escribir con tests. Luego usarlo desde el controlador. Debería tambien tratar los casos de actualización de un item inexistente o la creación de un item ya existente.
Otra nota: no puse ninguna vista MVC todavía. Pero ahora ya tengo los tests como para agregarlas con confianza. Cuando las agregue, la conducta esperada del controlador ya estará probada.
Nos leemos!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez