Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Test-Driven Development

Test-Driven Development

Test-Driven Development o TDD es una metodología de desarrollo de software que intenta de manera proactiva garantizar que nuestro código funciona como debería, además de prevenir y reducir el número de defectos y bugs de nuestro código. La idea principal de esta metodología es realizar de forma inicial las pruebas unitarias para el código que tenemos que implementar e ir creando un conjunto de pruebas que nos avisen inmediatamente si hemos introducido algún cambio que modifique su funcionamiento.

Desde que el TDD fue "redescubierto" por Kent Beck, ha sido una de las técnicas ágiles que más difusión ha alcanzado y goza de especial popularidad en estos momentos. Sin embargo, a menudo es mal aplicado y los equipos que lo implementan se ven aquejados de problemas comunes, que terminan haciendo que se abandone. Muchos desarrolladores piensan que desarrollar tests unitarios sale más caro, que es una pérdida de tiempo, pero sólo una reflexión, ¿cuánto tiempo pasáis depurando vuestro código? ¿cuántas veces habéis arreglado algún bug que se podría haber detectado con un test unitario?

En esta charla trataremos los siguientes puntos:
- Hablar sobre el origen de TDD
- Explicar brevemente cómo se realiza TDD
- Entrar en detalle de las ventajas e inconvenientes de TDD
- Justificar por qué TDD funciona de esta manera y qué conseguimos con ello
- Ver el lado oscuro de TDD trayendo opiniones relevantes que critican TDD y, a partir de ellas, ver qué cosas se podrían mejorar

Adrián Matellanes

April 19, 2018
Tweet

More Decks by Adrián Matellanes

Other Decks in Programming

Transcript

  1. A development technique where you must first write a test

    that fails before you write new code that passes the new test
  2. <?php use PHPUnit\Framework\TestCase; class UserTest extends TestCase { public function

    testTalk() { $user = new User(); $actual = $user->talk(); $expected = "Hello world!"; $this->assertEquals($expected, $actual); unset($user); } }
  3. <?php use PHPUnit\Framework\TestCase; class UserTest extends TestCase { public function

    testTalk() { $user = new User(); $actual = $user->talk(); $expected = "Hello world!"; $this->assertEquals($expected, $actual); unset($user); } } Setup
  4. <?php use PHPUnit\Framework\TestCase; class UserTest extends TestCase { public function

    testTalk() { $user = new User(); $actual = $user->talk(); $expected = "Hello world!"; $this->assertEquals($expected, $actual); unset($user); } } Execution
  5. <?php use PHPUnit\Framework\TestCase; class UserTest extends TestCase { public function

    testTalk() { $user = new User(); $actual = $user->talk(); $expected = "Hello world!"; $this->assertEquals($expected, $actual); unset($user); } } Validation
  6. <?php use PHPUnit\Framework\TestCase; class UserTest extends TestCase { public function

    testTalk() { $user = new User(); $actual = $user->talk(); $expected = "Hello world!"; $this->assertEquals($expected, $actual); unset($user); } } Teardown
  7. “If it's worth building, it's worth testing. If it's not

    worth testing, why are you wasting your time working on it?” Scott Ambler
  8. “The only way to make the deadline — the only

    way to constantly go fast — is to keep the code as clean as possible at all times.” Robert C. Martin
  9. <?php use PHPUnit\Framework\TestCase; function division($a, $b) { return $a /

    $b; } class CalculatorTest extends TestCase { public function testDivision() { $result = division(10, 5); $expected = 2; $this->assertEquals($expected, $result); } }
  10. Keep the unit small Minimize assertions Start with the failing

    test case Fast running tests Avoid fragile tests Rerun all test cases on each failure Don’t introduce dependencies between tests Follow standard naming conventions Use mock objects
  11. Hard to apply to existing legacy code Requirements misinterpretations False

    sense of security How many tests should you write? Complex scenarios Rapidly changing requirements Not having enough knowledge on unit testing and refactoring Restricted portability Writer/Reader with technical background
  12. Scenario: Dispense $50 cash in multiple denominations Given I have

    $100 in my account And I have a card with the PIN 1234 And I push my card into the machine And I enter 1234 for my PIN And I push the button next to Withdrawal And I push the button next to Checking When I push the button next to $50 Then a $20 bill should be ejected by the cash dispenser And a $20 bill should be ejected by the cash dispenser And a $10 bill should be ejected by the cash dispenser
  13. Scenario: Dispense $50 cash in multiple denominations Given I have

    $100 in my account And I have a card with the PIN 1234 And I push my card into the machine And I enter 1234 for my PIN And I push the button next to Withdrawal And I push the button next to Checking When I push the button next to $50 Then a $20 bill should be ejected by the cash dispenser And a $20 bill should be ejected by the cash dispenser And a $10 bill should be ejected by the cash dispenser
  14. Scenario: Dispense $50 cash in multiple denominations Given I have

    $100 in my account And I have a card with the PIN 1234 And I push my card into the machine And I enter 1234 for my PIN And I push the button next to Withdrawal And I push the button next to Checking When I push the button next to $50 Then a $20 bill should be ejected by the cash dispenser And a $20 bill should be ejected by the cash dispenser And a $10 bill should be ejected by the cash dispenser
  15. Scenario: Dispense $50 cash in multiple denominations Given I have

    $100 in my account And I have a card with the PIN 1234 And I push my card into the machine And I enter 1234 for my PIN And I push the button next to Withdrawal And I push the button next to Checking When I push the button next to $50 Then a $20 bill should be ejected by the cash dispenser And a $20 bill should be ejected by the cash dispenser And a $10 bill should be ejected by the cash dispenser
  16. Scenario: Dispense $50 cash in multiple denominations Given I have

    $100 in my account And I have a card with the PIN 1234 And I push my card into the machine And I enter 1234 for my PIN And I push the button next to Withdrawal And I push the button next to Checking When I push the button next to $50 Then a $20 bill should be ejected by the cash dispenser And a $20 bill should be ejected by the cash dispenser And a $10 bill should be ejected by the cash dispenser
  17. TDD Hard to apply to existing legacy code Inside out

    Fast execution time “That is wrong” Doing the thing right Technical writer/reader Low case coverage Poor maintainability Easy to apply to existing legacy code Outside in Slow execution time “Something is wrong” Doing the right thing Business writer/reader High case coverage High maintainability BDD
  18. References Test Driven Development: By Example by Kent Beck (2002)

    Refactoring by Kent Beck and Martin Fowler (1999) Succeeding with Agile by Mike Cohn (2009) Working Effectively with Unit Tests by Jay Fields (2014) The Art of Unit Testing by Roy Osherove (2013) Software Reliability: Principles and Practices by Glenford J. Myers (1976)