com.programmingchronicles.tdd.web.addressbook.TestAddContactController.java Source code

Java tutorial

Introduction

Here is the source code for com.programmingchronicles.tdd.web.addressbook.TestAddContactController.java

Source

/*
 * Copyright (C) 2010-2011, Pedro Ballesteros <pedro@theprogrammingchronicles.com>
 *
 * This file is part of The Programming Chronicles Test-Driven Development
 * Exercises(http://theprogrammingchronicles.com/)
 *
 * This copyrighted material is free software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This material is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this material. This copy is available in LICENSE-GPL.txt
 * file. If not, see <http://www.gnu.org/licenses/>.
 */

package com.programmingchronicles.tdd.web.addressbook;

import com.programmingchronicles.tdd.web.addressbook.AddContactController;
import com.programmingchronicles.tdd.addressbook.GlobalAddressBook;
import com.programmingchronicles.tdd.domain.Contact;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;
import javax.servlet.ServletException;
import org.junit.*;
import org.mockito.ArgumentCaptor;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

/**
 * Tests del controlador para el formulario de aadir contacto.
 *
 * <p>
 * Esta implementacion usa los Fakes proporcionados por la librera
 * de utilidades de testing de Spring, que proporciona una implementacin
 * completa de los objetos del contenedor de Servlets.</p>
 *
 * <p>
 * Es decir, tenemos ya codificados los Fakes que se han creado en
 * el ejercicio 5.7</p>
 *
 * <p><b>DISEO:</b><br/>
 * Se usa un patrn clsico de procesamiento de formularios
 * <ul>
 *    <li>El HTTP GET devuelve el formulario.
 *    <li>El HTTP POST procesa el formulario.
 *       <ul>
 *          <li> Si OK devuelve un redirect al navegador, evitando el doble POST.
 *          <li> Si Error devuelve de nuevo el formulario indicando los campos erroneos.
 *       </ul>
 * </ul>
 *
 * @author Pedro Ballesteros <pedro@theprogrammingchronicles.com>
 */
public class TestAddContactController {

    private static DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

    // Mocks
    private GlobalAddressBook mockAddressbook;

    // Object Under Tests
    private AddContactController controller;

    @Before
    public void setUp() {
        controller = new AddContactController();

        // Mock de GlobalAddressBook
        mockAddressbook = mock(GlobalAddressBook.class);

        // Se configura por Direct Injection el addressbook usado
        // por el controlador.
        controller.setAddressBook(mockAddressbook);

        // Las vistas ahora se configuran en el setup.
        controller.setFormView("formViewPath");
        controller.setSuccessedSubmitRedirect("redirectPath");
    }

    /**
     * Test del HTTP Get que muestra el formulario.
     *
     * @throws ServletException
     * @throws IOException
     */
    @Test
    public void testDoGetShowForm() throws ServletException, IOException {
        // Fakes de los parametros del doGet y doPost que amplian la interfaz
        // estandar permitiendo verificaciones sencillas por estado.
        //
        // Se utilizan los mocks de Spring Test Utilities.
        MockHttpServletRequest fakeRequest = new MockHttpServletRequest();
        MockHttpServletResponse fakeResponse = new MockHttpServletResponse();

        // Ejecucin del test.
        controller.doGet(fakeRequest, fakeResponse);

        // Verifica que el forward se realiza a la vista correcta, usando
        // las facilidades del Fake que permiten obtener el path del forward,
        // en lugar de realizar una validacin por interaccin.
        assertEquals("formViewPath", fakeResponse.getForwardedUrl());
    }

    /**
     * Test de HttpPost: Verifica que el contacto se aade a la agenda
     * usando el servicio de address book.
     *
     * <p><b>REFACTOFING:</b>
     *       El testDoPostGetParameters ya no era necesario, se prueba
     *       lo mismo en testDoPostAddContact. </p>
     *
     * <p>
     * El testDoPostAddContactRedirect tambin se ha fusionado aqui ya que tiene
     * ms sentido comprobar la funcionalidad completa.</p>
     */
    @Test
    public void testDoPostAddContact() throws ServletException, IOException, ParseException {
        // Fakes de los parametros del doGet y doPost que amplian la interfaz
        // estandar permitiendo verificaciones sencillas por estado.
        //
        // Se utilizan los mocks de Spring Test Utilities.
        MockHttpServletRequest fakeRequest = new MockHttpServletRequest();
        MockHttpServletResponse fakeResponse = new MockHttpServletResponse();

        // Ahora los fackes nos permiten configurar los parametros de entrada
        // del mtodo testeado. Esto no lo permitan los mocks del contenedor
        // ya que HttpServletRequest no tiene un "setParameters".
        fakeRequest.setParameter("firstName", "Pedro");
        fakeRequest.setParameter("surname", "Ballesteros");
        fakeRequest.setParameter("birthday", "8/1/1974");
        fakeRequest.setParameter("phone", "69696969");

        // Ejecucin del test.
        controller.doPost(fakeRequest, fakeResponse);

        // Verifica que se llama al addContact del mock del addressbook
        ArgumentCaptor<Contact> argument = ArgumentCaptor.forClass(Contact.class);
        verify(mockAddressbook).addContact(argument.capture());

        // En el verify anterior capturamos el argumento con el que se llama
        // a la agenda, y podemos validar que se aade el contacto correcto.
        Contact contact = argument.getValue();
        assertEquals("Pedro", contact.getFirstName());
        assertEquals("Ballesteros", contact.getSurname());
        assertEquals(dateFormat.parse("8/1/1974"), contact.getBirthday());
        assertEquals("69696969", contact.getPhone());

        // Verifica con el fake que no se ha intentado crear el modelo de errores
        assertNull(fakeRequest.getAttribute("errors"));

        // El Fake del HttpServletResponse ahora nos permite verificar por estado
        // la respuesta del doPost.

        // Verifica que se entrega un redirect de navegador al response, ahora
        // el fake nos permite acceder a datos de la respuesta.
        assertEquals("redirectPath", fakeResponse.getRedirectedUrl());
    }

    /**
     * Test Http Post: Verifica un post con todos los parametros vacos.
     *
     * @throws ServletException
     * @throws IOException
     */
    @Test
    public void testDoPostNullParams() throws ServletException, IOException {
        // Fakes de los parametros del doGet y doPost que amplian la interfaz
        // estandar permitiendo verificaciones sencillas por estado.
        //
        // Se utilizan los mocks de Spring Test Utilities.
        MockHttpServletRequest fakeRequest = new MockHttpServletRequest();
        MockHttpServletResponse fakeResponse = new MockHttpServletResponse();

        // Ejecucin del test para comprobar que se establece el modelo
        // en este caso los errores.
        controller.doPost(fakeRequest, fakeResponse);

        // Verifica que no se ha intentado aadir el contacto ya que
        // el nombre es obligatorio.
        verify(mockAddressbook, never()).addContact(any(Contact.class));

        // Verifica que se ha creado un modelo con los errores con un
        // setAtribute. Decidimos que se introducirn en un Map<String, String>.

        // Ahora se puede verificar por estado, porque sabemos que nuestro fake
        // devuelve valores reales establecidos con el setAttribute.
        Map<String, String> errors = (Map<String, String>) fakeRequest.getAttribute("errors");
        assertTrue(errors.containsKey("firstName"));
        assertFalse(errors.containsKey("surname"));
        assertFalse(errors.containsKey("birthday"));
        assertFalse(errors.containsKey("phone"));

        // IMPORTANTE:
        //   No se han comprobado los textos de error, en un test unitario no se
        //   deben probar la IU. Dichas pruebas estaran en tests de IU (test de sistema).

        // En caso de error la peticin se debe dirigir a la vista del formulario
        // de nuevo, que ahora mostrar los campos de entrada erroneos.

        // Ahora se puede verificar por estado ya que el fake del response nos
        // permite acceder al path con el que se hizo el forward.
        assertEquals("formViewPath", fakeResponse.getForwardedUrl());
    }

    /**
     * Test Http Post: Verifica que se puede aadir un contacto con
     * solo el nombre.
     *
     * @throws ServletException
     * @throws IOException
     */
    @Test
    public void testDoPostOnlyName() throws ServletException, IOException {
        // Fakes de los parametros del doGet y doPost que amplian la interfaz
        // estandar permitiendo verificaciones sencillas por estado.
        //
        // Se utilizan los mocks de Spring Test Utilities.
        MockHttpServletRequest fakeRequest = new MockHttpServletRequest();
        MockHttpServletResponse fakeResponse = new MockHttpServletResponse();

        // El request solo tendr el parametros del nombre
        fakeRequest.setParameter("firstName", "Pedro");

        // Ejecucin del test.
        controller.doPost(fakeRequest, fakeResponse);

        // Verifica que se llama al addContact del mock del addressbook
        ArgumentCaptor<Contact> argument = ArgumentCaptor.forClass(Contact.class);
        verify(mockAddressbook).addContact(argument.capture());

        // En el verify anterior capturamos el argumento con el que se llama
        // a la agenda, y podemos validar que se aade el contacto correcto.
        Contact contact = argument.getValue();
        assertEquals("Pedro", contact.getFirstName());
        assertNull(contact.getSurname());
        assertNull(contact.getBirthday());
        assertNull(contact.getPhone());

        // Verifica que no se ha creado el modelo de errores.
        assertNull(fakeRequest.getAttribute("errors"));

        // Verifica que se llama al redirect del response con el parametro correcto.
        assertEquals("redirectPath", fakeResponse.getRedirectedUrl());
    }
}