Test cuenta corriente solucion

  junit
package prácticaunidad3;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;


import org.junit.Rule;
import org.junit.rules.ExpectedException;

/**
 * Realmente nos deberían dar os requisitos do sistema e o a información do API (os métodos) 
 * a implementar, Por exemplo, en este caso nos terían que decir:
 * 
 * Debemos facer un Test JUnit que nos permita verificar o ingreso e retirada de fondos dunha
 * Conta Corrente.
 * 
 * O ingreso ten que ser unha cantidade positiva. Si se intenta ingresar unha cantidade negativa, se 
 * lanzará un erro (exception) co texto "No se puede ingresar una cantidad negativa"
 * O saldo quedará incrementado na cantidade ingresada.
 * 
 * A retirada ten que indicarse cunha cantidade positiva. Si se intenta retirar unha cantidade negativa
 * se lanzará un erro (exception) co texto "No se puede ingresar una cantidad negativa". Si se
 * intentan retirar máis cartos dos dispoñibles no saldo se debe lanzar un erro (exception) co texto
 * "No existe suficiente saldo". O saldo quedará decrementado na cantidade retirada.
 * 
 * A clase CCuenta dispón dos métodos:
 * 
 * public CCuenta ()    --> Constructor por defecto. Crea un CCuenta con saldo 0
 * public CCuenta (String nom, String cue, double sal, double tipo)   --> Constructor inicializando os atributos da clase
 * public void asignarNombre(String nom) --> Pon nome ao titular da conta
 * public String obtenerNombre() --> Devolve o nome do titular da conta
 * public double estado () --> Devolve o saldo da conta
 * public void ingresar(double cantidad) throws Exception --> Permite ingresar unha cantidade da conta
 * public void retirar (double cantidad) throws Exception --> Permite retirar unha cantidade da conta
 * public String obtenerCuenta () --> Permite obter o número de conta
 * 
 * 
 * A partir de aquí deseñaríamos os casos de proba para o ingreso e a retirada.
 * O deseño dun caso de uso consiste simplemente en elexir uns datos de entrada o suficientemente
 * representativos para garantizar o correcto funcionamento da clase (para o que se poden empregar
 * distintos métodos vistos na unidade, como valores límite) e calcular os resultados que
 * se deben obter.
 * A codificación dos casos de test, consiste na escritura dun pequeno programa ou varios programas
 * pequenos que subministren esas entradas e comproben si o resultado é correcto. Si o resultado
 * devolto non é correcto é que a unidade (clase) que estamos probando non cumple os requisitos
 * funcionais, polo que non é correcta.
 * 
 * JUnit non é máis que un "framework" que nos facilita a construción deses programas de proba
 * e proporciona un xeito estándar de facelo, facilitando a reutilización, documentación  e sistematización
 * dos tests de proba.
 * 
 * Neste caso:
 *   --> Test de Ingresar
 *          Caso 1: O saldo é 0 e ingresamos unha cantidade negativa
 *                  Debe lanzarse a excepción co texto "No se puede ingresar una cantidad negativa"
 *          Caso 2: O saldo é 100.750 e ingresamos 3000.25
 *                  O saldo resultante debe ser 3101
 *          Caso 4: O saldo é  2147483640 (cerca do límite de int) e ingreso 300
 *                  O saldo resultante debe ser 2147483940
 *          Caso 5: O saldo é de 9007199254740992 (busco o límite enteiro dun double) e ingreso 1
 *                  Se debe lanzar unha excepción co texto "No se puede exceder el saldo máximo"
 * 
 *  ---> Test de Retirar
 *          Caso 1: Retiro 150 euros dunha conta con saldo 100
 *                  Debe lanzarse unha excepción co texto "No existe suficiente saldo"
 *          Caso 2: Retiro -150 euros dunha conta con saldo 100
 *                  Debe lanzarse unha excepción co texto "No se puede retirar una cantidad negativa"
 *          Caso 3: Retiro 135.75 euros dunha conta con saldo 136
 *                  O saldo resultante debe ser 0.25
 *  ---> Ingresar e Retirar
 *          Caso : Partimos con saldo 100.234, ingresamos 100.200 e retiramos 140.034
 *                 Debe quedar un saldo de 60.40
 * 
 * Este sería o deseño dos test de unidade. Agora os codificaremos usando o "framework"
 * de testing JUnit (existen outros).
 * A verificación das excepcións se pode facer de tres modos:
 *  a) Capturando a excepción 
 *  b) Mediante unha anotación (non permite verificar o texto da excepción)
 *  c) Mediante unha regla JUnit (Rule)
 * 
 * Fixádevos que si o test falla, non é porque o test de unidade esté mal nin porque
 * esté mal codificado en JUnit, é porque a clase CCuenta.java NON E CORRECTA.
 * 
 * Si o saldo é demasiado grande non se comporta como debe.
 * 
 * Para probar podedes arranxar CCuenta.java engadindo esto ao principio do método
 * ingresar:
 *   if ((saldo>0)&&(saldo+cantidad == saldo)) throw new Exception("No se puede exceder el saldo máximo");
 * 
 * @author dessinweb
 */
public class CCuentaTest {
    CCuenta conta;
    
    public CCuentaTest() {
        System.out.println("Constructor. Execútase unha vez ao comenzo do test");
    }
    
     @BeforeClass
    public static void setUpClass() {
        System.out.println("METODO ANOTADO COMO BeforeClass. (o nome do método non importa)");
        System.out.println("BeforeClass. Se executa UNHA VEZ antes de crear a o obxecto CCuentaTest");
        System.out.println("BeforeClass. Sirve para tarefas de inicialización");
    }
    
    @AfterClass
    public static void tearDownClass() {
        System.out.println("METODO ANOTADO COMO AfterClass. (o nome do método non importa)");
        System.out.println("AfterClass: Se executa UNHA VEZ despois de todos os tests");
        System.out.println("AfterClass: Sirve para tarefas de limpeza");
    }
    
    @Before
    public void setUp() {
        System.out.println("METODO ANOTADO COMO Before. (o nome do método non importa)");
        System.out.println("Before: Se executa antes de CADA test");
        System.out.println("Before. Sirve para tarefas de inicialización");

        // Antes de cada test creamos unha conta con saldo 0, para non ter influencia
        // de un test en outro. Recordemos que os test se executan en un orde aleatorio
        conta=new CCuenta("Cuenta Test","NumCuenta",0.0,0.0);

    }
    
    @After
    public void tearDown() {
        System.out.println("METODO ANOTADO COMO After. (o nome do método non importa)");
        System.out.println("After: Se executa despois de cada test");
        System.out.println("After: Sirve para tarefas de limpeza");
    }
    
    
    /** TEST 1: INGRESO
     * Comprobo a excepción cunha anotación... non podo verificar a mensaxe, 
     * únicamente que a Exception se lanza... é útil si se lanzara unha Exception moi
     * específica na que non fora relevante a mensaxe. Ademáis este método é pouco
     * apropiado a esta situación, xa que lle sirven as Exception que lanzan os 
     * assert fallidos, dando o test como pasado incorrectamente.
     * Outro problema, é que unha vez que se lanza a Exception non se continúan
     * verificando o resto de asserts, polo que o temos que separar en dous métodos.
     * 
 *          Caso 1: O saldo é 0 e ingresamos unha cantidade negativa
 *                  Debe lanzarse a excepción co texto "No se puede ingresar una cantidad negativa"
 *          Caso 2: O saldo é 100.750 e ingresamos 3000.25
 *                  O saldo resultante debe ser 3101
 *          Caso 4: O saldo é  2147483650 (cerca do límite de int) e ingreso 300
 *                  O saldo resultante debe ser 2147483950
 *          Caso 5: O saldo é de 9007199254740992 (busco o límite enteiro dun double) e ingreso 1
 *                  Debería lanzar un erro co texto "No se puede exceder el saldo máximo"
     */
    @Test(expected=Exception.class)
    public void testIngresoNegativoWithAnnotatedExceptionExample() throws Exception {
        conta.ingresar(-100);
    }
    
    @Test
    public void testIngresoAnnotatedExceptionExample() throws Exception {
        // Non teño un método para cambiar o saldo, teño que crear unha nova conta
        conta=new CCuenta("Cuenta Test","NumCuenta",100.750,0.0);
        conta.ingresar(3000.25);
        assertEquals("O saldo debe ser 3101",3101.00,conta.estado(),0.0);
        
        conta=new CCuenta("Cuenta Test","NumCuenta",2147483650.0,0.0);
        conta.ingresar(300);
        assertEquals("O saldo debe ser 2147483950",2147483950.0,conta.estado(),0.0);
    }
    
    @Test(expected=Exception.class)
    public void testIngresoOverflowWithAnnotatedExceptionExample() throws Exception {
        conta=new CCuenta("Cuenta Test","NumCuenta",9007199254740992.0,0.0);
        conta.ingresar(1);    
    }
    
    /**
     * E o mesmo test que nos tres métodos anteriores, pero capturando 
     * a Exception. Podemos verificar a mensaxe e non temos os problemas
     * indicados anteriormente.
     */
    @Test
    public void testIngresoWithCapturedExceptionExample() throws Exception {
        try {
            conta.ingresar(-100);
            fail("Se debería lanzar un error por ingresar una cantidad negativa");
        } catch(Exception e) {
            // Comprobamos o texto da exception
            if (!e.getMessage().equals("No se puede ingresar una cantidad negativa")) {
               fail("A Exception obtenida: "+e.getMessage()+", non corresponde coa desexada");
            }
        }
        conta=new CCuenta("Cuenta Test","NumCuenta",100.750,0.0);
        conta.ingresar(3000.25);
        assertEquals("O saldo debe ser 3101",3101.00,conta.estado(),0.0);
        
        conta=new CCuenta("Cuenta Test","NumCuenta",2147483650.0,0.0);
        conta.ingresar(300);
        assertEquals("O saldo debe ser 2147483950",2147483950.0,conta.estado(),0.0);
        
        try {
            conta=new CCuenta("Cuenta Test","NumCuenta",9007199254740992.0,0.0);
            conta.ingresar(1);
            fail("Se debería lanzar un error por exceder el límite de saldo");
        } catch(Exception e) {
             // Comprobamos o texto da exception
            if (!e.getMessage().equals("No se puede exceder el saldo máximo")) {
               fail("A Exception obtenida: "+e.getMessage()+", non corresponde coa desexada");
            }
        }
    }
    
    /**
     * E o mesmo test que os anteriores, pero usando unha Rule para comprobar
     * a Exception. Podemos verificar a mensaxe e non temos os problemas
     * indicados anteriormente.
     * PERO, so podemos controlar o lanzamento de unha exception por test
     * debemos separalo en dous.
     */
    @Rule
    public ExpectedException expectedEx = ExpectedException.none();

    @Test
    public void testIngresoNegativoWithRuleExceptionExample() throws Exception {
        expectedEx.expect(Exception.class);
        expectedEx.expectMessage("No se puede ingresar una cantidad negativa");
        conta.ingresar(-100);
    }
    
    /**
     * Necesito dividir o test en dous, xa que unha vez que se lanza a Exception
     * o codigo de debaixo nunca se chega a executar
     * @throws Exception 
     */
    @Test
    public void testIngresoWithRuleExceptionExample() throws Exception {
        conta=new CCuenta("Cuenta Test","NumCuenta",100.750,0.0);
        conta.ingresar(3000.25);
        assertEquals("O saldo debe ser 3101",3101.00,conta.estado(),0.0);
        
        conta=new CCuenta("Cuenta Test","NumCuenta",2147483650.0,0.0);
        conta.ingresar(300);
        assertEquals("O saldo debe ser 2147483950",2147483950.0,conta.estado(),0.0);
    }

    @Test
    public void testIngresoOverflowWithRuleExceptionExample() throws Exception {
        expectedEx.expect(Exception.class);
        expectedEx.expectMessage("No se puede exceder el saldo máximo");
        conta=new CCuenta("Cuenta Test","NumCuenta",9007199254740992.0,0.0);
        conta.ingresar(1);
    }
    
    /**
     * Test de Retirar.
 *          Caso 1: Retiro 150 euros dunha conta con saldo 100
 *                  Debe lanzarse unha excepción co texto "No existe suficiente saldo"
 *          Caso 2: Retiro -150 euros dunha conta con saldo 100
 *                  Debe lanzarse unha excepción co texto "No se puede retirar una cantidad negativa"
 *          Caso 3: Retiro 135.75 euros dunha conta con saldo 136
 *                  O saldo resultante debe ser 0.25
     */
    @Test
    public void testRetirada() throws Exception {
        // Retirada Excesiva
        try {
            conta=new CCuenta("Cuenta Test","NumCuenta",100.0,0.0);
            conta.retirar(150);
            fail("Debe lanzarse una Exception con el texto 'No existe suficiente saldo'");
        } catch(Exception e) {
            if (!e.getMessage().equals("No existe suficiente saldo")) 
                fail("A Excepción lanzada non é a apropiada");
        }
        
        // Retirada Negativa
        try {
            conta.retirar(-150);
            fail("Debe lanzarse una Exception con el texto 'No se puede retirar una cantidad negativa'");
        } catch(Exception e) {
            if (!e.getMessage().equals("No se puede retirar una cantidad negativa")) 
                fail("A Excepción lanzada non é a apropiada");
        }
        conta=new CCuenta("Cuenta Test","NumCuenta",136.0,0.0);
        conta.retirar(135.75);
        assertEquals("Test Retirada 136-135.25, Deben quedar 0.25",0.25,conta.estado(),0.0);
    }
    
    /**
     * Test de Retirada e Ingreso
 * ---> Ingresar e Retirar
 *          Caso : Partimos con saldo 100.234, ingresamos 100.200 e retiramos 140.034
 *                 Debe quedar un saldo de 60.40
     */
    @Test
    public void testIngresoRetirada() throws Exception {
        conta=new CCuenta("Cuenta Test","NumCuenta",100.234,0.0);
        conta.ingresar(100.200);
        conta.retirar(140.034);
        
        // Como vemos, este assert falla. Se debe a falta de precisión de double
        // xestionando os números enteiros, normalmente temos que indicar no último
        // parámetro o erro "aceptable". O deberíamos facer en TODOS os assert anteriores..
        
        //assertEquals("Deben quedar 60.40",60.40,conta.estado(),0.0);
             
        // Este sería o assertEquals CORRECTO
        assertEquals("Deben quedar 60.40",60.40,conta.estado(),0.00000000001);
    }
}

Deja un comentario