Developer Vago 1

Unit testing

VigoJUG

Axenda

  • (19:30) VigoJUG e VigoTech

  • Developer Vago

  • Motivación unit test

  • JUnit 4, JUnit 5, Spock

  • (20:30) Charlas lostrego e debate

  • (21:00) Kahoot

  • (21:30) Refrescos

VigoJUG

  • Un meetup o primeiro martes de cada mes

  • ¿Te animas cunha charla?. Licencias de JetBrains ;-)

  • Outras iniciativas: obradoiro virtual #VigoJUG-taller

  • Canal de slack #VigoJUG en http://www.vigotech.org

sponsors
vigotech

Developer Vago

  • Charla sobre unha temática xeral preparada polo VigoJUG

  • De utilidade para todo o mundo, independentemente da tua experiencia

  • Facelo ameno, non estamos para teorías cuánticas ;-)

  • Rematar con charlas lóstrego e/ou debates abertos

Non sexades tímidos: ¡¡participar!!

baby

Motivación das probas unitarias

É mais áxil

Especialmente en proxectos grandes, por exemplo, para encontrar bugs.

Acompañar a resolución de bugs cun test é unha moi boa idea.

Calidade do código

Facilita os cambios e simplifica a integración

Documenta

Mellora o deseño

Se é mais doado de testar, é mais modular.

¿Facer os test primeiro? TDD.

Reduce costes

Exemplo: Fibonacci

Entrevista

Implementar un programa que devolva o número n da secuencia de Fibonacci. n pasase coma parámetro.

1, 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55 , 89 , 144

Solución Java

public class BadFibonacci {

    // Fixme: very bad performance
    private static int fibonacci(int n) {
        if (n <= 1) return n; else
            return fibonacci(n-1) + fibonacci(n-2);
    }

    public static void main(String[] args) {
        System.out.println("Result: " + fibonacci(4));
    }
}

JUnit 4

@test e assertTrue

    @Test
    public void fibonacciTestSimple() {
        FibonacciWithJUnit4 f = new FibonacciWithJUnit4();
        assertTrue(f.fibonacci(4) == 3);
    }

assertFalse

    @Test
    public void fibonacciTestZero() {
        FibonacciWithJUnit4 f = new FibonacciWithJUnit4();
        assertFalse(f.fibonacci(1) == 0 );
    }

assertEquals

    @Test
    public void improvedFibonacciTestSimple() {
        FibonacciWithJUnit4 f = new FibonacciWithJUnit4();
        assertEquals(f.fibonacci(4), 3);
    }

@Ignore

    @Ignore("Demo, no hacerlo en casa")
    @Test
    public void ignoredFibonacciTestSimple() {
        FibonacciWithJUnit4 f = new FibonacciWithJUnit4();
        assertEquals(f.fibonacci(4), 0);
    }

assertThat

    @Test
    public void testAssertThatBothContainsString() {
        FibonacciWithJUnit4 f = new FibonacciWithJUnit4();
        String temp = fibonacci(1) + " " + fibonacci(4);
        assertThat(temp, both(containsString("0")).and(containsString("3")));
    }

Exceptions

    @Test(expected = NullPointerException.class)
    public void testException() {
        FibonacciWithJUnit4 f = new FibonacciWithJUnit4();
        Integer i = 0;
        i = null;
        f.fibonacci(i.intValue());
    }

timeout

    @Test(timeout = 5000)
    public void testTimeout() {
        try {
            fibonacci(100);
        } catch (Exception e) {
            // Don't do this at home
        }
    }

@AfterClass, @BeforeClass, @After

    private static FibonacciWithJUnit4 f2;

    @BeforeClass
    public static void setupTest() {
        f2 = new FibonacciWithJUnit4();
    }

    @AfterClass
    public static void clear() {
        f2 = null;
    }

    @Test
    public void fibonacciTestSimpleWithBefore() {
        assert (f2.fibonacci(4) == 3);
    }

    @After
    public void done() {
        System.out.println("Done!");
    }

Test parametrizados con JUnit 4

JUnit 5

Introducción

  • Mais granular

  • Permite mais runners e extensións

  • Java 8

  • Compatibilidade con JUnit 4

@Test e assert

    @Test
    public void fibonacciTestSimple() {
        FibonacciWithJUnit5 f = new FibonacciWithJUnit5();
        Assertions.assertTrue(
                fibonacci(4) == 3,
                () -> "Fibonnaci number " + 4 + " is " + 3);
    }

@Disabled

    @Disabled("Demo, non o facer na casa ;-)")
    @Test
    public void ignoredFibonacciTestSimple() {
        FibonacciWithJUnit5 f = new FibonacciWithJUnit5();
        assertEquals(f.fibonacci(4), 0);
    }

Composed tests with assertAll

    @Test
    public void testAssertThatBothContainsString() {
        FibonacciWithJUnit5 f = new FibonacciWithJUnit5();
        String temp = f.fibonacci(1) + " " + f.fibonacci(4);
        Assertions.assertAll("Our composed test",
                () -> Assertions.assertTrue(temp.contains("1")),
                () -> Assertions.assertTrue(temp.contains("3"))
        );
    }

Exception

    @Test()
    public void testException() {
        FibonacciWithJUnit5 f = new FibonacciWithJUnit5();
        Integer i = null;
        Assertions.assertThrows(NullPointerException.class, () -> f.fibonacci(i.intValue()));
    }

Timeout

    @Test()
    public void testTimeout() throws InterruptedException {
        Assertions.assertTimeout(Duration.ofMillis(1), () -> fibonacci(30));
        //Assertions.assertTimeoutPreemptively(Duration.ofSeconds(1), () -> fibonacci(100));
    }

@AfterAll, @BeforeAll, @AfterEach

    private static FibonacciWithJUnit5 f2;

    @BeforeAll
    public static void setupTest() {
        f2 = new FibonacciWithJUnit5();
    }

    @AfterAll
    public static void clear() {
        f2 = null;
    }

    @Test
    public void fibonacciTestSimpleWithBefore() {
        assert (f2.fibonacci(4) == 3);
    }

    @AfterEach
    public void done() {
        System.out.println("Done!");
    }

Test parametrizados con JUnit 5

Spock Framework

Simple test with assert

    def "Simple test"() {
        setup:
        BadFibonacci f = new BadFibonacci()

        expect:
        f.fibonacci(1) == 1
        assert f.fibonacci(4) == 3
    }

Simple test with false

    def "Simple test with Zero"() {
        setup:
        BadFibonacci f = new BadFibonacci()

        expect:
        f.fibonacci(1) != 0

Groovy Truth

    def "not assertEquals but Groovy Truth"() {
        setup:
        BadFibonacci f = new BadFibonacci()

        expect:
        assert f.fibonacci(1)
    }

@Ignore e @IgnoreRest

    @Ignore
    // @IgnoreRest
    def "Simple ignored test"() {
        setup:
        BadFibonacci f = new BadFibonacci()

        expect:
        f.fibonacci(1) == 0
    }

Exceptions

    @FailsWith(MissingMethodException)
    // @FailsWith(SpockAssertionError)
    def "Simple test with Exception"() {
        setup:
        BadFibonacci f = new BadFibonacci()
        Integer i = 0

        when:
        i = null

        then:
        notThrown(f.fibonacci(i))

    }

Test composto

    def "composed test with string"() {
        setup:
        BadFibonacci f = new BadFibonacci()

        when:
        def temp = f.fibonacci(1) + " " + f.fibonacci(4);

        then:
        temp.contains '1'
        and:
        temp.contains '3'
    }

Timeout

    @Ignore
    @Timeout(value = 200, unit = MILLISECONDS)
    def "Simple test with TimeOut"() {
        setup:
        BadFibonacci f = new BadFibonacci()

        expect:
        f.fibonacci(100) == 0
    }

Métodos de axuda

    def setup() {}          // run before every feature method
    def cleanup() {}        // run after every feature method
    def setupSpec() {}     // run before the first feature method
    def cleanupSpec() {}   // run after the last feature method

    @Subject
    BadFibonacci f2 = new BadFibonacci()

Test parametrizado con Groovy

    def "parametrized test"() {
        setup:
        BadFibonacci f = new BadFibonacci()

        expect:
        f.fibonacci(index) == fibonacciNumber

        where:
        index     | fibonacciNumber
        1         | 1
        2         | 1
        3         | 2
    }

Mock e Stub

Mock

interface Subscriber {
    String receive(String message)
}

Subscriber subscriber = Mock()

Stub

subscriber.receive(_) >> "ok"

Integración con gradle (e maven)

Reporte tests

Reporte cobertura

Lightning talks?

Debate aberto

¿Facedes tests unitarios?

¿Qué librería usades para testing?

  • JUnit 4

  • JUnit 5

  • Spock

  • Outra?

  • Non fago tests

¿Onde paramos?

  • ¿Métodos públicos?

  • ¿100% de cobertura?

¿Qué usades para mocks?

¿Algo mais?

Kahoot

¿Dúbidas?