Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

TDD anti patterns - episode 3 - With Juan Pablo

Marabesi
February 10, 2022

TDD anti patterns - episode 3 - With Juan Pablo

Testing practices has increasing its adoption by developers, shifting left the test responsibilities
And increasing the quality of the code, besides that, continuous testing is an agile practice that impacts the software development life cycle.

In this talk we are going to focus on the following TDD anti-patterns: The nitpicker, The secret catcher, The dodger and The Loudmouth. This is the third out of 6 in the testing anti-patterns series.

Marabesi

February 10, 2022
Tweet

More Decks by Marabesi

Other Decks in Programming

Transcript

  1. TDD - EP 3 codurance.com Testing anti-patterns - The nitpicker,

    The secret catcher, The dodger, The Loudmouth
  2. Matheus Marabesi Hello there, you can call me Marabesi, But

    my name is Matheus Marabesi, I work at Codurance as a Software Craftsperson. I enjoy talking about anything related to: testing, patterns and gamification. You can find me at @MatheusMarabesi or https://marabesi.com Codurance Crafting Code
  3. 1. Intro - Recap 2. The nitpicker 3. The secret

    catcher 4. The dodger 5. The Loudmouth 6. Wrapping up Crafting code Agenda
  4. The Liar The Giant The Mockery The Inspector Generous Leftovers

    The Local Hero The Nitpicker The Secret Catcher The Dodger The Loudmouth Anti patterns The Greedy Catcher Excessive Setup The Sequencer Hidden Dependency The Enumerator The Stranger The Operating System Evangelist Success Against All Odds The Free Ride The One The Peeping Tom The Slow Poke James Carr - TDD Anti-Patterns
  5. The Liar 4 The Giant 5 The Mockery 1 The

    Inspector 7 Generous Leftovers 5 The Local Hero 7 The Nitpicker The Secret Catcher The Dodger The Loudmouth Anti patterns The Greedy Catcher Excessive Setup 3 The Sequencer Hidden Dependency The Enumerator The Stranger The Operating System Evangelist Success Against All Odds The Free Ride The One The Peeping Tom The Slow Poke 6
  6. The Liar 4 The Giant 5 The Mockery 1 The

    Inspector 7 Generous Leftovers 5 The Local Hero 7 The Nitpicker The Secret Catcher The Dodger The Loudmouth Anti patterns The Greedy Catcher Excessive Setup 3 The Sequencer Hidden Dependency The Enumerator The Stranger The Operating System Evangelist Success Against All Odds The Free Ride The One The Peeping Tom The Slow Poke 6
  7. Anti patterns - Survey takeaways 1. Survey notes: Javascript, PHP

    and Java were the most used programming languages 2. Survey notes: Practitioners usually informally learn TDD 3. Survey notes: Companies argue that TDD requires more time to complete a task and the team don't have time for it
  8. 2. Anti-patterns - Episode 3 The nitpicker, The secret catcher,

    The dodger and The Loudmounth Getting started
  9. The Liar The Giant The Mockery The Inspector Generous Leftovers

    The Local Hero The Nitpicker The Secret Catcher The Dodger The Loudmouth Anti patterns The Greedy Catcher Excessive Setup The Sequencer Hidden Dependency The Enumerator The Stranger The Operating System Evangelist Success Against All Odds The Free Ride The One The Peeping Tom The Slow Poke James Carr - TDD Anti-Patterns
  10. The Liar The Giant The Mockery The Inspector Generous Leftovers

    The Local Hero The Nitpicker8 The Secret Catcher7 The Dodger8 The Loudmouth8 Anti patterns The Greedy Catcher Excessive Setup The Sequencer Hidden Dependency The Enumerator The Stranger The Operating System Evangelist Success Against All Odds The Free Ride The One The Peeping Tom The Slow Poke James Carr - TDD Anti-Patterns
  11. 2. The nitpicker - 🏆8 A unit test which compares

    a complete output when it’s really only interested in small parts of it, so the test has to continually be kept in line with otherwise unimportant details. Endemic in web application testing. Crafting code
  12. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertExactJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  13. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertExactJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  14. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertExactJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  15. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertExactJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  16. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertExactJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  17. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertExactJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  18. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertExactJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  19. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  20. public function testDeleteApplication() { $response = $this->postApplication(); $this->assertFalse($response->error); $this->delete('api/application/' .

    $response->data) ->assertJson([ 'data' => (string) $response->data, 'error' => false ]); } PHP - Laravel
  21. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  22. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  23. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  24. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  25. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  26. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  27. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  28. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  29. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  30. describe('#getSignedCookies()', function() { it('should create cookies object', function(done) { var

    result = CloudfrontUtil.getSignedCookies( 'http://foo.com', defaultParams); expect(result).to.have.property('CloudFront-Policy'); expect(result).to.have.property('CloudFront-Signature'); expect(result).to.have.property('CloudFront-Key-Pair-Id'); done(); }); }); Javascript - chai
  31. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  32. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  33. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  34. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  35. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  36. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  37. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  38. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  39. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  40. @Test fun `should calculate CFR correctly by monthly and the

    time split works well ( cross a calendar month)`() { val requestBody = """ { skipped code } """.trimIndent() RestAssured .given() .contentType(ContentType.JSON) .body(requestBody) .post("/api/pipeline/metrics") .then() .statusCode(200) .body("changeFailureRate.summary.value", equalTo(30.0F)) .body("changeFailureRate.summary.level", equalTo("MEDIUM")) .body("changeFailureRate.details[0].value", equalTo("NaN")) .body("changeFailureRate.details[1].value", equalTo("NaN")) .body("changeFailureRate.details[2].value", equalTo(30.0F)) } Kotlin - RestAssured
  41. • Use what you need • It can be generalized

    to other applications (CLI for example) Points of attention
  42. 3. The Secret Catcher - 🏆7 A test that at

    first glance appears to be doing no testing due to the absence of assertions, but as they say, “the devil’s in the details.” The test is really relying on an exception to be thrown when a mishap occurs, and is expecting the testing framework to capture the exception and report it to the user as a failure. Crafting code
  43. test('it handles error when removing credit card ', async ()

    => { const data = await Payment.asyncData(asyncDataContext); data.paymentMethod = PaymentMethod.CREDIT_CARD; const { getAllByText } = render(Payment, { mocks, data() { return { ...data }; }, }); const [removeButton] = getAllByText(Remove'); await fireEvent.click(removeButton); }); Jest - Javascript
  44. test('it handles error when removing credit card ', async ()

    => { const data = await Payment.asyncData(asyncDataContext); data.paymentMethod = PaymentMethod.CREDIT_CARD; const { getAllByText } = render(Payment, { mocks, data() { return { ...data }; }, }); const [removeButton] = getAllByText('Remove'); await fireEvent.click(removeButton); }); Jest - Javascript
  45. test('it handles error when removing credit card ', async ()

    => { const data = await Payment.asyncData(asyncDataContext); data.paymentMethod = PaymentMethod.CREDIT_CARD; const { getAllByText } = render(Payment, { mocks, data() { return { ...data }; }, }); const [removeButton] = getAllByText('Remove'); await fireEvent.click(removeButton); }); Jest - Javascript
  46. test('it handles error when removing credit card ', async ()

    => { const data = await Payment.asyncData(asyncDataContext); data.paymentMethod = PaymentMethod.CREDIT_CARD; const { getAllByText } = render(Payment, { mocks, data() { return { ...data }; }, }); const [removeButton] = getAllByText('Remove'); await fireEvent.click(removeButton); }); Jest - Javascript
  47. test('it handles error when removing credit card ', async ()

    => { const data = await Payment.asyncData(asyncDataContext); data.paymentMethod = PaymentMethod.CREDIT_CARD; const { getAllByText } = render(Payment, { mocks, data() { return { ...data }; }, }); const [removeButton] = getAllByText('Remove'); await fireEvent.click(removeButton); }); Jest - Javascript
  48. test('it handles error when removing credit card ', async ()

    => { const data = await Payment.asyncData(asyncDataContext); data.paymentMethod = PaymentMethod.CREDIT_CARD; const { getAllByText } = render(Payment, { mocks, data() { return { ...data }; }, }); const [removeButton] = getAllByText('Remove'); await fireEvent.click(removeButton); }); Jest - Javascript
  49. test('it handles error when removing credit card ', async ()

    => { const data = await Payment.asyncData(asyncDataContext); data.paymentMethod = PaymentMethod.CREDIT_CARD; const { getAllByText } = render(Payment, { mocks, data() { return { ...data }; }, }); const [removeButton] = getAllByText('Remove'); await fireEvent.click(removeButton); }); Jest - Javascript 👀
  50. test('it handles error when removing credit card ', async ()

    => { const data = await Payment.asyncData(asyncDataContext); data.paymentMethod = PaymentMethod.CREDIT_CARD; const { getAllByText } = render(Payment, { mocks, data() { return { ...data }; }, }); const [removeButton] = getAllByText('Remove'); await fireEvent.click(removeButton); expect(getByText('Some error')).toBeInTheDocument(); }); Jest - Javascript
  51. Software engineering unlocked, Dr. McKayla Because well, if, if you

    know, a smoke test could also execute a lot of the code base. Actually just, you know, make sure that the code run somehow without verifying that, you know, the inputs and outputs are matching and so on. Dr. Mauricio’s Aniche
  52. 4. The Dodger - 🏆8 A unit test which has

    lots of tests for minor (and presumably easy to test) side effects, but never tests the core desired behavior. Sometimes you may find this in database access related tests, where a method is called, then the test selects from the database and runs assertions against the result. Crafting code
  53. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  54. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  55. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  56. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  57. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  58. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  59. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  60. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  61. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  62. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  63. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  64. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  65. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  66. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  67. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  68. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  69. /** * Tests that objects works as expected. */ public

    function testObject(): void { $author = Author::createFromArray($this->getSampleId(), $this->getSampleValues()); $this->assertEquals($this->getSampleId(), $author->getId()); $this->assertEquals($this->getSampleValues()['name']['given'], $author->getNameGiven()); $this->assertEquals($this->getSampleValues()['name']['family'], $author->getNameFamily()); $this->assertEquals($this->getSampleValues()['country'], $author->getCountry()); $this->assertEquals($this->getSampleValues()['org']['name'], $author->getOrgName()); $this->assertEquals($this->getSampleValues()['org']['unit'], $author->getOrgUnit()); $this->assertEquals($this->getSampleValues()['homepage'], $author->getHomepage()); $this->assertEquals($this->getSampleValues()['description'], $author->getDescription()); $this->assertEquals($this->getSampleValues()['image'], $author->getImage()); $this->assertEquals($this->getSampleValues()['identification'], $author->getIdentification()); $this->assertEquals($this->getSampleValues()['identification']['email'], $author->getIdentification('email')); $this->assertEquals([], $author->getIdentification('not exist')); $this->assertEquals($author->checksum(), $author->checksum()); } Drupal - PHP
  70. • 1-1 one test class to one production class •

    Focus on implementation details rather than behavior Points of attention
  71. 5. The Loudmouth - 🏆8 A unit test (or test

    suite) that clutters up the console with diagnostic messages, logging messages, and other miscellaneous chatter, even when tests are passing. Crafting code
  72. test.each([['function']])( 'should not bubble up the error when a invalid

    source code is provided', (code) => { const strategy = jest.fn(); const result = Reason(code, strategy); expect(strategy).toHaveBeenCalledTimes(0); expect(result).toBeFalsy(); } ); Console log - Javascript
  73. test.each([['function']])( 'should not bubble up the error when a invalid

    source code is provided', (code) => { const strategy = jest.fn(); const result = Reason(code, strategy); expect(strategy).toHaveBeenCalledTimes(0); expect(result).toBeFalsy(); } ); Console log - Javascript
  74. test.each([['function']])( 'should not bubble up the error when a invalid

    source code is provided', (code) => { const strategy = jest.fn(); const result = Reason(code, strategy); expect(strategy).toHaveBeenCalledTimes(0); expect(result).toBeFalsy(); } ); Console log - Javascript
  75. test.each([['function']])( 'should not bubble up the error when a invalid

    source code is provided', (code) => { const strategy = jest.fn(); const result = Reason(code, strategy); expect(strategy).toHaveBeenCalledTimes(0); expect(result).toBeFalsy(); } ); Console log - Javascript
  76. const reason = function(code, strategy) { try { const ast

    = esprima.parseScript(code); if (ast.body.length > 0) { return strategy(ast); } } catch (error) { /* eslint-disable-next-line */ console.warn(error); return false; } }; Console log - Javascript
  77. const reason = function(code, strategy) { try { const ast

    = esprima.parseScript(code); if (ast.body.length > 0) { return strategy(ast); } } catch (error) { /* eslint-disable-next-line */ console.warn(error); return false; } }; Console log - Javascript
  78. const reason = function(code, strategy) { try { const ast

    = esprima.parseScript(code); if (ast.body.length > 0) { return strategy(ast); } } catch (error) { /* eslint-disable-next-line */ console.warn(error); return false; } }; Console log - Javascript
  79. const reason = function(code, strategy) { try { const ast

    = esprima.parseScript(code); if (ast.body.length > 0) { return strategy(ast); } } catch (error) { /* eslint-disable-next-line */ console.warn(error); return false; } }; Console log - Javascript
  80. const originalConsole = globalThis.console; beforeEach(() => { globalThis.console = {

    warn: jest.fn(), error: jest.fn(), log: jest.fn() }; }); afterEach(() => { globalThis.console = originalConsole; }); Console log - Javascript
  81. const originalConsole = globalThis.console; beforeEach(() => { globalThis.console = {

    warn: jest.fn(), error: jest.fn(), log: jest.fn() }; }); afterEach(() => { globalThis.console = originalConsole; }); Console log - Javascript
  82. const originalConsole = globalThis.console; beforeEach(() => { globalThis.console = {

    warn: jest.fn(), error: jest.fn(), log: jest.fn() }; }); afterEach(() => { globalThis.console = originalConsole; }); Console log - Javascript
  83. const originalConsole = globalThis.console; beforeEach(() => { globalThis.console = {

    warn: jest.fn(), error: jest.fn(), log: jest.fn() }; }); afterEach(() => { globalThis.console = originalConsole; }); Console log - Javascript
  84. • Clean up if not needed • Threat the logs

    as a feature, test drive them Points of attention
  85. • The nitpicker • The secret catcher • The dodger

    • The Loudmounth • and many more! What we covered
  86. Matheus Marabesi Hello there, you can call me Marabesi, But

    my name is Matheus Marabesi, I work at Codurance as a Software craftsperson. I enjoy talking about anything related to: testing, patterns and gamification. You can find me at @MatheusMarabesi or https://marabesi.com Codurance Crafting Code