Pruebas unitarias en Java con JUnit 5

    Introducci贸n

    JUnit es un marco de prueba popular para Java. El uso simple es muy sencillo y JUnit 5 trajo algunas diferencias y comodidades en comparaci贸n con JUnit 4.

    El c贸digo de prueba est谩 separado del c贸digo del programa real y, en la mayor铆a de los IDE, los resultados / salida de la prueba tambi茅n est谩n separados de la salida del programa, lo que proporciona una estructura legible y conveniente.

    Instalaci贸n de JUnit 5

    Instalar JUnit es tan simple como incluir las dependencias:

    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.4.0-RC1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.4.0-RC1</version>
        <scope>test</scope>
    </dependency>
    

    Puede elegir simplemente crear las clases de prueba en la misma carpeta que el resto de su c贸digo, pero se recomienda tener un directorio separado para las pruebas. Otra cosa a tener en cuenta son las convenciones de nomenclatura. Si deseamos probar completamente nuestro c贸digo, cada clase debe tener una clase de prueba correspondiente llamada – [classname]Test.

    Generalmente, una estructura de proyecto recomendada es:

    Nota: Es muy recomendable que importe JUnit5 usando el staticmodificador, har谩 que el uso de los m茅todos proporcionados sea mucho m谩s limpio y m谩s legible.

    Diferencias entre JUnit 4 y JUnit 5

    Una de las ideas principales detr谩s de la nueva versi贸n de JUnit es utilizar las caracter铆sticas que Java 8 trajo a la mesa (principalmente lambdas) para facilitar la vida de todos. Se han cambiado algunas cosas menores: el mensaje opcional de que se imprimir铆a una aserci贸n si fallaba es ahora el 煤ltimo argumento “opcional”, en lugar de ser inconvenientemente el primero.

    JUnit 5 consta de tres proyectos (JUnit Platform, JUnit Jupiter y JUnit Vintage), por lo que habr谩 varias importaciones diferentes, aunque JUnit Jupiter ser谩 nuestro enfoque principal.

    Algunas otras diferencias incluyen:

    • El JDK m铆nimo para JUnit 4 era JDK 5, mientras que JUnit 5 requiere al menos JDK 8
    • El @Before, @BeforeClass, @After, y @AfterClasslas anotaciones son ahora el m谩s f谩cil de leer como los @BeforeEach, @BeforeAll, @AfterEach, y @AfterAllanotaciones
    • @Ignore es ahora @Disable
    • @Category es ahora @Tag
    • Soporte para clases de prueba anidadas y una f谩brica de pruebas adicional para pruebas din谩micas

    La anotaci贸n @Test

    Usaremos una clase de calculadora simple para demostrar las capacidades b谩sicas de JUnit. Por ahora, nuestra Calculatorclase se ve as铆:

    public class Calculator {
        float add(float a, float b) {
            return a + b;
        }
    
        int divide(int a, int b) {
            return a/b;
        }
    }
    

    No hace nada especial, pero nos permitir谩 realizar las pruebas. Seg煤n las convenciones de nomenclatura, CalculatorTestnace la clase:

    class CalculatorTest {
    
        @Test
        void additionTest() {
            Calculator calc = new Calculator();
            assertEquals(2, calc.add(1,1), "The output should be the sum of the two arguments");
        }
    }
    

    La @Testanotaci贸n le dice a la JVM que el siguiente m茅todo es una prueba. Esta anotaci贸n es necesaria antes de cada m茅todo de prueba.

    El m茅todo assertEquals()y todos los m茅todos de “afirmaci贸n” funcionan de manera similar: afirman (es decir, se aseguran) de que lo que estamos comprobando es true. En este caso, estamos afirmando que los dos argumentos que pasamos son iguales (consulte la Nota a continuaci贸n), en caso de que no lo sean, la prueba fallar谩.

    El primer argumento es generalmente el valor de retorno esperado y el segundo es el valor de retorno real del m茅todo que estamos probando. Si estos dos son iguales, la afirmaci贸n est谩 satisfecha y la prueba pasa.

    El tercer argumento es opcional pero muy recomendable: es el mensaje personalizado que aparecer谩 cuando una prueba no salga como deber铆a. Puede que no importe con los programas peque帽os, pero es una buena pr谩ctica agregar estos mensajes para que quien trabaje con su c贸digo m谩s adelante (o un futuro usted) pueda descubrir f谩cilmente lo que no funcion贸.

    Ejecutamos las pruebas simplemente ejecutando la CalculatorTestclase (podemos hacerlo aunque no tenga un mainm茅todo):

    Si cambiamos la assertEquals()l铆nea a algo que no es correcto, como:

    assertEquals(1, calc.add(1,1), "The output should be the sum of the two arguments");
    

    Recibiremos un mensaje de falla de prueba adecuado:

    Nota: Es muy importante comprender que en assertEquals()realidad usa el .equals()m茅todo y no el ==operador. Hay un m茅todo JUnit separado llamado assertSame()que usa en ==lugar de .equals().

    M茅todos de afirmaci贸n

    JUnit 5 viene con muchos m茅todos de afirmaci贸n . Algunos de ellos son solo m茅todos de conveniencia que se pueden reemplazar f谩cilmente por un m茅todo assertEquals()o assertSame(). Sin embargo, se recomienda utilizar estos m茅todos de conveniencia en su lugar, para facilitar la lectura y el mantenimiento.

    Por ejemplo, la llamada assertNull(object, message)se puede reemplazar por assertSame(null, object, message), pero se recomienda la forma anterior.

    Echemos un vistazo a las afirmaciones a nuestra disposici贸n. En general, se explican por s铆 mismos:

    • assertEquals() y assertNotEquals()
    • assertSame() y assertNotSame()
    • assertFalse() y assertTrue()
    • assertThrows() afirma que el m茅todo generar谩 una excepci贸n dada, cuando se enfrente al valor de retorno del m茅todo probado
    • assertArrayEquals(expectedArray, actualArray, optionalMsg)compara las dos matrices y pasa solo si tienen los mismos elementos en las mismas posiciones; de lo contrario, falla. Si ambas matrices lo son null, se consideran iguales.
    • assertIterableEquals(Iterable<?> expected, Iterable<?> actual, optionalMsg)se asegura de que los iterables esperados y reales sean profundamente iguales. Dado que este m茅todo toma an Iterablecomo los dos argumentos, los iterables que pasamos no necesitan ser del mismo tipo (podemos pasar ay LinkedListan ArrayList, por ejemplo). Sin embargo, sus iteradores deben devolver elementos iguales en el mismo orden que los dem谩s. Nuevamente, si ambos lo son null, se consideran iguales.
    • assertLinesMatch(List<String> expected, List<String> actual, optionalMsg)es un m茅todo un poco m谩s complejo, ya que toma varios pasos antes de declarar que los argumentos pasados 鈥嬧媙o son iguales y funciona solo con Strings:
    • Verifica si expected.equals(actual)regresa true, si lo hace, pasa a las siguientes entradas.
    • Si el Paso 1 no regresa true, la expectedcadena actual se trata como una expresi贸n regular, por lo que el m茅todo verifica actual.matches(expected)si lo hace y, si lo hace, pasa a las siguientes entradas.
    • Si ninguno de los dos pasos anteriores regresa true, el 煤ltimo intento que hace el m茅todo es verificar si la siguiente l铆nea es una l铆nea de avance r谩pido. Una l铆nea de avance r谩pido comienza y termina con “>>”, entre los cuales hay un n煤mero entero (omite el n煤mero de l铆neas designadas) o una cadena.
    • <T extends Throwable> T assertThrows(Class<T> expectedType, Executable exec, optionalMsg)comprueba que la ejecuci贸n de Executablearroja una excepci贸n de expectedTypey devuelve esa excepci贸n. Si no se lanza ninguna excepci贸n o si la excepci贸n lanzada no es del expectedType, la prueba falla.
    • assertTimeout(Duration timeout, Executable exec, optionalMsg)comprueba que execcompleta su ejecuci贸n antes de que se exceda el tiempo de espera dado. Dado que execse ejecuta en el mismo hilo que el del c贸digo de llamada, la ejecuci贸n no se interrumpir谩 de forma preventiva si se excede el tiempo de espera. En otras palabras, execfinaliza su ejecuci贸n independientemente de timeout, el m茅todo simplemente verifica despu茅s si se ejecut贸 lo suficientemente r谩pido.
    • assertTimeoutPreemptively(Duration timeout, Executable exec, optionalMsg)comprueba que la ejecuci贸n de execcompleta antes de que se exceda el tiempo de espera dado, pero a diferencia del assertTimeoutm茅todo, este m茅todo se ejecuta execen un subproceso diferente y abortar谩 preventivamente la ejecuci贸n si timeoutse excede el proporcionado .
    • assertAll(Exectutable... executables) throws MultipleFailuresErrory assertAll(Stream<Executable> executables) throws MultipleFailuresErrorhace algo muy 煤til. Es decir, si quisi茅ramos usar varias afirmaciones en una prueba (no es necesariamente malo si lo hacemos), suceder铆a algo muy molesto si todas salieran mal. A saber:
      @Test
      void additionTest() {
          Calculator calc = new Calculator();
          assertEquals(100, calc.add(1,1), "Doesn't add two positive numbers properly");
          assertEquals(100, calc.add(-1,1), "Doesn't add a negative and a positive number properly");
          assertNotNull(calc, "The calc variable should be initialized");
      }
      

      Cuando falla la primera afirmaci贸n, no veremos c贸mo fueron las otras dos. Lo cual puede ser especialmente frustrante, ya que puede corregir la primera afirmaci贸n con la esperanza de que solucione toda la prueba, solo para descubrir que la segunda afirmaci贸n tambi茅n fall贸, solo que no la vio ya que la primera afirmaci贸n que fall贸 “ocult贸” ese hecho. :

      assertAll()resuelve este problema ejecutando todas las afirmaciones y luego mostr谩ndole el error incluso si fallaron varias afirmaciones. La versi贸n reescrita ser铆a:

      @Test
      void additionTest() {
          Calculator calc = new Calculator();
          assertAll(
              () -> assertEquals(100, calc.add(1,1), "Doesn't add two positive numbers properly"),
              () -> assertEquals(100, calc.add(-1,1), "Doesn't add a negative and a positive number properly"),
              () -> assertNotNull(calc, "The calc variable should be initialized")
          );
      }
      

      Ahora obtendremos un resultado de prueba m谩s informativo:

      Es bueno entender que assertAll()b谩sicamente verifica si alguno de los ejecutables arroja una excepci贸n, ejecut谩ndolos todos independientemente, y todos los que arrojan una excepci贸n se agregan en el MultipleFailuresErrorque arroja el m茅todo. Sin embargo, para problemas serios, como OutOfMemoryErrorla ejecuci贸n se detendr谩 inmediatamente y la excepci贸n se volver谩 a lanzar tal cual, pero enmascarada como una excepci贸n no verificada (tiempo de ejecuci贸n).

    Nota: Es posible que haya notado que String optionalMsgse excluye de las declaraciones del m茅todo. JUnit 5 proporciona una peque帽a optimizaci贸n al optionalMsg. Por supuesto, podemos usar un simple Stringcomo nuestro optionalMsg; sin embargo, independientemente de c贸mo vaya la prueba (si falla o no), Java seguir谩 generando eso String, aunque es posible que nunca se imprima. Esto no importa cuando hacemos algo como:

    assertEquals(expected, actual, "The test failed for some reason");
    

    Pero si tuvi茅ramos algo parecido a:

    assertEquals(expected, actual, "The test failed because " + (Math.sqrt(50) + Math.scalb(15,7) + Math.cosh(10) + Math.log1p(23)) + " is not a pretty number");
    

    Realmente no desea que se optionalMsgcargue algo as铆, independientemente de si Java planea imprimirlo.

    La soluci贸n es usar un Supplier<String>. De esta manera podemos utilizar los beneficios de la evaluaci贸n perezosa, si nunca ha o铆do hablar del concepto, es b谩sicamente Java diciendo “No calcular茅 nada que no necesite. 驴Necesito esto Stringahora? 驴No? Entonces no lo crear谩 “. La evaluaci贸n perezosa aparece varias veces en Java.

    Esto se puede hacer simplemente agregando () ->antes de nuestro mensaje opcional. Para que se convierta en:

    assertEquals(expected, actual, () -> "The test failed because " + (Math.sqrt(50) + Math.scalb(15,7) + Math.cosh(10) + Math.log1p(23)) + " is not a pretty number");
    

    Esta es una de las cosas que no eran posibles antes de JUnit 5, porque Lambdas no se introdujo en Java en ese momento y JUnit no pudo aprovechar su utilidad.

    Prueba de anotaciones

    En esta parte, presentaremos algunas otras anotaciones, adem谩s de la @Testanotaci贸n necesaria . Una cosa que debemos entender es que para cada m茅todo de prueba, Java crea una nueva instancia de la clase de prueba.

    Es una mala idea declarar variables globales que se cambian dentro de diferentes m茅todos de prueba, y es una idea especialmente mala esperar cualquier tipo de orden de prueba, 隆no hay garant铆as de en qu茅 orden se ejecutar谩n los m茅todos de prueba!

    Otra mala idea es tener que inicializar constantemente la clase que queremos probar si no es necesario. Veremos c贸mo evitarlo pronto, pero antes de eso, echemos un vistazo a las anotaciones disponibles:

    • @BeforeEach: Se llama a un m茅todo con esta anotaci贸n antes de cada m茅todo de prueba, muy 煤til cuando queremos que los m茅todos de prueba tengan alg煤n c贸digo en com煤n. Los m茅todos deben tener un voidtipo de retorno, no deben ser privatey no deben ser static.
    • @BeforeAll: Un m茅todo con esta anotaci贸n se llama solo una vez, antes de que se ejecute cualquiera de las pruebas, se usa principalmente en lugar de @BeforeEachcuando el c贸digo com煤n es costoso, como establecer una conexi贸n de base de datos. 隆El @BeforeAllm茅todo debe ser el staticpredeterminado! Tampoco debe ser privatey debe tener un voidtipo de retorno.
    • @AfterAll: Un m茅todo con esta anotaci贸n se llama solo una vez, despu茅s de que se haya llamado a cada m茅todo de prueba. Normalmente se utiliza para cerrar conexiones establecidas por @BeforeAll. El m茅todo debe tener un voidtipo de retorno, no debe ser privatey debe ser static.
    • @AfterEach: Se llama a un m茅todo con esta anotaci贸n despu茅s de que cada m茅todo de prueba finaliza su ejecuci贸n. Los m茅todos deben tener un voidtipo de retorno, no deben ser privatey no deben ser static.

    Para ilustrar cu谩ndo se ejecuta cada uno de estos m茅todos, agregaremos algo de sabor a nuestra CalculatorTestclase y, mientras lo hacemos, demostraremos el uso del assertThrows()m茅todo:

    class CalculatorTest {
    
        Calculator calc;
    
        @BeforeAll
        static void start() {
            System.out.println("inside @BeforeAll");
        }
    
        @BeforeEach
        void init() {
            System.out.println("inside @BeforeEach");
            calc = new Calculator();
        }
    
        @Test
        void additionTest() {
            System.out.println("inside additionTest");
            assertAll(
                () -> assertEquals(2, calc.add(1,1), "Doesn't add two positive numbers properly"),
                () -> assertEquals(0, calc.add(-1,1), "Doesn't add a negative and a positive number properly"),
                () -> assertNotNull(calc, "The calc variable should be initialized")
            );
        }
    
        @Test
        void divisionTest() {
            System.out.println("inside divisionTest");
            assertThrows(ArithmeticException.class, () -> calc.divide(2,0));
        }
    
        @AfterEach
        void afterEach() {
            System.out.println("inside @AfterEach");
        }
    
        @AfterAll
        static void close() {
            System.out.println("inside @AfterAll");
        }
    }
    

    Lo que nos da el resultado de:

    inside @BeforeAll
    
    inside @BeforeEach
    inside divisionTest
    inside @AfterEach
    
    
    inside @BeforeEach
    inside additionTest
    inside @AfterEach
    
    inside @AfterAll
    

    Esto tambi茅n nos muestra que, a pesar de que el additionTest()m茅todo se declara primero, no garantiza que se ejecutar谩 primero.

    Otras anotaciones

    Antes de JUnit 5, los m茅todos de prueba no pod铆an tener ning煤n par谩metro, pero ahora s铆. Los usaremos mientras demostramos las nuevas anotaciones.

    @Discapacitado

    Una anotaci贸n simple y 煤til que simplemente deshabilita cualquier m茅todo de prueba, es decir, la prueba no se ejecutar谩 y el resultado de la prueba mostrar谩 que la prueba en particular fue deshabilitada:

    @Disabled
    @Test
    void additionTest() {
        // ...
    }
    

    Da el siguiente resultado para ese m茅todo de prueba:

    void main.CalculatorTest.additionTest() is @Disabled
    
    @DisplayName

    Otra anotaci贸n simple que cambia el nombre mostrado del m茅todo de prueba.

    @DisplayName("Testing addition")
    @Test
    void additionTest() {
        // ...
    }
    
    @Etiqueta

    La @Taganotaci贸n es 煤til cuando queremos crear un “paquete de prueba” con las pruebas seleccionadas. Las etiquetas se utilizan para filtrar qu茅 pruebas se ejecutan:

    class SomeTest {
        @Tag("a")
        @Test
        void test1() {
            // ...
        }
        @Tag("a")
        @Test
        void test2() {
            // ...
        }
        @Tag("b")
        @Test
        void test3() {
            // ...
        }
    }
    

    Entonces, si quisi茅ramos ejecutar solo pruebas que tengan la etiqueta “a”, ir铆amos a Ejecutar -> Editar configuraciones y cambiar铆amos los siguientes dos campos antes de ejecutar la prueba:

    @RepetidoPrueba

    Esta anotaci贸n funciona igual que la @Testanotaci贸n, pero ejecuta el m茅todo de prueba el n煤mero de veces especificado. Cada iteraci贸n de prueba puede tener su propio nombre, mediante el uso de una combinaci贸n de marcadores de posici贸n din谩micos y texto est谩tico. Los marcadores de posici贸n disponibles actualmente son:

    • {displayName}: nombre para mostrar del @RepeatedTestm茅todo
    • {currentRepetition}: el recuento de repeticiones actual
    • {totalRepetitions}: el n煤mero total de repeticiones

    El nombre predeterminado de cada iteraci贸n es “repetici贸n {currentRepetition} de {totalRepetitions}”.

    //@RepeatedTest(5)
    @DisplayName("Repeated Test")
    @RepeatedTest(value = 5, name = "{displayName} -> {currentRepetition}")
    void rptdTest(RepetitionInfo repetitionInfo) {
        int arbitrary = 2;
        System.out.println("Current iteration: " + repetitionInfo.getCurrentRepetition());
    
        assertEquals(arbitrary, repetitionInfo.getCurrentRepetition());
    }
    

    El RepetitionInfopar谩metro no es necesario, pero podemos acceder a 茅l si necesitamos esos datos. Obtenemos una pantalla limpia con respecto a cada iteraci贸n cuando ejecutamos esto:

    @ParametrizedTest

    Las pruebas parametrizadas tambi茅n permiten ejecutar una prueba varias veces, pero con diferentes argumentos.

    Funciona de manera similar, por @RepeatedTestlo que no volveremos a pasar por todo, solo por las diferencias.

    Debe agregar al menos una fuente que proporcionar谩 los argumentos para cada iteraci贸n y luego agregar un par谩metro del tipo requerido al m茅todo.

    @ParameterizedTest
    @ValueSource(ints = {6,8,2,9})
    void lessThanTen(int number) {
        assertTrue(number < 10, "the number isn't less than 10");
    }
    

    El m茅todo recibir谩 los elementos de la matriz uno por uno:

    @ValueSourcees solo un tipo de anotaci贸n que acompa帽a @ParametrizedTest. Para obtener una lista de otras posibilidades, consulte la documentaci贸n .

    @Anidado

    Esta anotaci贸n nos permite agrupar las pruebas donde tenga sentido hacerlo. Es posible que deseemos separar las pruebas que tratan de la suma de las pruebas que tratan de la divisi贸n, la multiplicaci贸n, etc. y nos proporciona un camino f谩cil para @Disableciertos grupos por completo. Tambi茅n nos permite probar y hacer oraciones completas en ingl茅s como resultado de nuestra prueba, haci茅ndolo extremadamente legible.

    @DisplayName("The calculator class: ")
    class CalculatorTest {
        Calculator calc;
    
        @BeforeEach
        void init() {
            calc = new Calculator();
        }
    
        @Nested
        @DisplayName("when testing addition, ")
        class Addition {
            @Test
            @DisplayName("with positive numbers ")
            void positive() {
                assertEquals(100, calc.add(1,1), "the result should be the sum of the arguments");
            }
    
            @Test
            @DisplayName("with negative numbers ")
            void negative() {
                assertEquals(100, calc.add(-1,-1), "the result should be the sum of the arguments");
            }
        }
    
        @Nested
        @DisplayName("when testing division, ")
        class Division {
            @Test
            @DisplayName("with 0 as the divisor ")
            void throwsAtZero() {
                assertThrows(ArithmeticException.class, () -> calc.divide(2,0), "the method should throw and ArithmeticException");
            }
        }
    }
    
    @TestInstance

    Esta anotaci贸n se usa solo para anotar la clase de prueba con @TestInstance(Lifecycle.PER_CLASS)para decirle a JUnit que ejecute todos los m茅todos de prueba en una sola instancia de la clase de prueba, y no cree una nueva instancia de la clase para cada m茅todo de prueba.

    Esto nos permite usar variables de nivel de clase y compartirlas entre los m茅todos de prueba (generalmente no se recomienda), como inicializar recursos fuera de un m茅todo @BeforeAllo @BeforeEachy @BeforeAllya @AfterAllno es necesario static. Por tanto, el modo “por clase” tambi茅n hace posible el uso de m茅todos @BeforeAlly @AfterAllen @Nestedclases de prueba.

    La mayor铆a de las cosas que podemos hacer @TestInstance(Lifecycle.PER_CLASS)se pueden hacer con staticvariables. Tenemos que tener cuidado de restablecer todas las variables que necesitaban restablecerse a un cierto valor en @BeforeEach, que generalmente se restablec铆an cuando la clase se reiniciaba cada vez.

    Supuestos

    Adem谩s de las afirmaciones antes mencionadas, tenemos supuestos. Cuando una suposici贸n no es cierta, la prueba no se ejecuta en absoluto. Las suposiciones se utilizan normalmente cuando no tiene sentido seguir ejecutando una prueba si no se cumplen determinadas condiciones, y la mayor铆a de las veces la propiedad que se est谩 probando es algo externo, no directamente relacionado con lo que estamos probando. Hay algunos m茅todos de suposici贸n sobrecargados:

    • assumeTrue(boolean assumption, optionalMsg)y assumeFalse(boolean assumption, optionalMsg)solo ejecutar谩 la prueba si lo proporcionado assumptiones verdadero y falso, respectivamente. Se optionalMsgmostrar谩 solo si la suposici贸n no es cierta.
    • assumingThat(boolean assumption, Executable exec)– si assumptiones verdadero, execse ejecutar谩; de lo contrario, este m茅todo no hace nada.

    Se BooleanSupplierpuede usar A en lugar de regular boolean.

    class CalculatorTest {
    
        Calculator calc;
        boolean bool;
    
        @BeforeEach
        void init() {
            System.out.println("inside @BeforeEach");
            bool = false;
            calc = new Calculator();
        }
    
        @Test
        void additionTest() {
            assumeTrue(bool, "Java sees this assumption isn't true -> stops executing the test.");
            System.out.println("inside additionTest");
            assertAll(
                    () -> assertEquals(2, calc.add(1,1), "Doesn't add two positive numbers properly"),
                    () -> assertEquals(0, calc.add(-1,1), "Doesn't add a negative and a positive number properly"),
                    () -> assertNotNull(calc, "The calc variable should be initialized"));
        }
    
        @Test
        void divisionTest() {
            assumeFalse(0 > 5, "This message won't be displayed, and the test will proceed");
            assumingThat(!bool, () -> System.out.println("uD83DuDC4C"));
            System.out.println("inside divisionTest");
            assertThrows(ArithmeticException.class, () -> calc.divide(2,0));
        }
    }
    

    Lo que nos dar铆a la salida:

    inside @BeforeEach
    馃憣
    inside divisionTest
    
    
    inside @BeforeEach
    
    
    org.opentest4j.TestAbortedException: Assumption failed: Java sees this assumption isn't true -> stops executing the test.
    

    Conclusi贸n y consejos

    La mayor铆a de nosotros probamos el c贸digo ejecutando manualmente el c贸digo, ingresando alguna entrada o haciendo clic en algunos botones y verificando la salida. Estas “pruebas” suelen ser un escenario de caso com煤n y un mont贸n de casos extremos en los que podemos pensar. Esto est谩 relativamente bien con proyectos peque帽os, pero se vuelve completamente un desperdicio en algo m谩s grande. Probar un m茅todo en particular es particularmente malo: o System.out.println()el resultado y lo verificamos, o lo ejecutamos a trav茅s de algunas ifdeclaraciones para ver si se ajusta a la expectativa, luego cambiamos el c贸digo cada vez que queremos verificar qu茅 sucede cuando pasamos otros argumentos al m茅todo . Analizamos visual y manualmente en busca de algo inusual.

    JUnit nos brinda una forma limpia de administrar nuestros casos de prueba y separa la prueba del c贸digo del c贸digo en s铆. Nos permite realizar un seguimiento de todo lo que debe probarse y nos muestra lo que no funciona de manera ordenada.

    Generalmente, desea probar el caso com煤n de todo lo que pueda. Incluso los m茅todos simples y directos, solo para asegurarse de que funcionan como deber铆an. Esta podr铆a incluso ser la parte m谩s importante de las pruebas automatizadas, ya que cada vez que cambia algo en su c贸digo o agrega un nuevo m贸dulo, puede ejecutar las pruebas para ver si ha roto el c贸digo o no, para ver si todo sigue funcionando. como lo hizo antes de la “mejora”. Por supuesto, los casos extremos tambi茅n son importantes, especialmente para m茅todos m谩s complejos.

    Siempre que encuentre un error en su c贸digo, es una muy buena idea escribir una prueba antes de solucionar el problema. Esto asegurar谩 que si el error se repite, no necesitar谩 perder tiempo averiguando qu茅 sali贸 mal nuevamente . Una prueba simplemente fallar谩 y sabr谩 d贸nde est谩 el problema.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *