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

TDD anti patterns - episode 2 - TDD anti patterns - With Giulio Perrone

Ed39ca0d44a6e6cdefc76ac548de5f41?s=47 Marabesi
January 20, 2022

TDD anti patterns - episode 2 - TDD anti patterns - With Giulio Perrone

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, if not testing your code, what will it be then?

In this talk we are going to focus on the following TDD anti-patterns: The mockery, The inspector, Generous leftovers and The local hero. Those are the next set of anti pattern that we are going to cover. If you missed the last session, you can check it on Codurance's platform at https://app.livestorm.co/codurance/testing-anti-patterns-workshop.

Ed39ca0d44a6e6cdefc76ac548de5f41?s=128

Marabesi

January 20, 2022
Tweet

More Decks by Marabesi

Other Decks in Technology

Transcript

  1. TDD - EP 2 codurance.com Testing anti-patterns - The mockery,

    The inspector, The Generous leftovers and The local hero
  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. Giulio Perrone Hello there! As you may have guessed, my

    name is Giulio and I work at Codurance as a Software Craftsperson! I enjoy writing katas, discussing algorithms and playing video-games. Codurance Crafting Code
  4. 1. Intro - Recap 2. The mockery - MM 3.

    The inspector - GP 4. The Generous leftovers - MM 5. The local hero - GP 6. Wrapping up Crafting code Agenda
  5. 1. Recap Episode 1, testing assertions Getting started

  6. 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
  7. The Liar 4 The Giant 5 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 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
  8. 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. The anti patterns covered were related to test last 4. Subjects we touched around testability: SOLID, Object calisthenics, Non-determinism and the test pyramid
  9. 2. Anti-patterns - Episode 2 The mockery, The inspector, Generous

    leftovers and The local hero Getting started
  10. 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
  11. The Liar The Giant 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 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
  12. Survey

  13. 2. The mockery - 🏆1 Sometimes mocking can be good,

    and handy. But sometimes developers can lose themselves and in their effort to mock out what isn’t being tested. In this case, a unit test contains so many mocks, stubs, and/or fakes that the system under test isn’t even being tested at all, instead data returned from mocks is what is being tested. Crafting code
  14. class PaymentService( private val userRepository: UserRepository, private val paymentGateway: PaymentGateway

    ) { fun process( user: User, paymentDetails: PaymentDetails ): Boolean { if (userRepository.exists(user)) { return paymentGateway.pay(paymentDetails) } return false } } Repository - Kotlin
  15. class PaymentService( private val userRepository: UserRepository, private val paymentGateway: PaymentGateway

    ) { fun process( user: User, paymentDetails: PaymentDetails ): Boolean { if (userRepository.exists(user)) { return paymentGateway.pay(paymentDetails) } return false } } Repository - Kotlin
  16. class PaymentService( private val userRepository: UserRepository, private val paymentGateway: PaymentGateway

    ) { fun process( user: User, paymentDetails: PaymentDetails ): Boolean { if (userRepository.exists(user)) { return paymentGateway.pay(paymentDetails) } return false } } Repository - Kotlin
  17. class PaymentService( private val userRepository: UserRepository, private val paymentGateway: PaymentGateway

    ) { fun process( user: User, paymentDetails: PaymentDetails ): Boolean { if (userRepository.exists(user)) { return paymentGateway.pay(paymentDetails) } return false } } Repository - Kotlin
  18. class TestPaymentService { private val userRepository: UserRepository = mockk() private

    val paymentGateway: PaymentGateway = mockk() private val paymentService = PaymentService( userRepository, paymentGateway ) @Test fun paymentServiceProcessPaymentFor() { val user: User = User() every { userRepository.exists(any()) } returns true every { paymentGateway.pay(any()) } returns true assertTrue(paymentService.process(user, PaymentDetails())) } } Repository - Kotlin
  19. class TestPaymentService { private val userRepository: UserRepository = mockk() private

    val paymentGateway: PaymentGateway = mockk() private val paymentService = PaymentService( userRepository, paymentGateway ) @Test fun paymentServiceProcessPaymentForUser() { val user: User = User() every { userRepository.exists(any()) } returns true every { paymentGateway.pay(any()) } returns true assertTrue(paymentService.process(user, PaymentDetails())) } } Repository - Kotlin
  20. class TestPaymentService { private val userRepository: UserRepository = mockk() private

    val paymentGateway: PaymentGateway = mockk() private val paymentService = PaymentService( userRepository, paymentGateway ) @Test fun paymentServiceProcessPaymentForUser() { val user: User = User() every { userRepository.exists(any()) } returns true every { paymentGateway.pay(any()) } returns true assertTrue(paymentService.process(user, PaymentDetails())) } } Repository - Kotlin
  21. class TestPaymentService { private val userRepository: UserRepository = mockk() private

    val paymentGateway: PaymentGateway = mockk() private val paymentService = PaymentService( userRepository, paymentGateway ) @Test fun paymentServiceProcessPaymentForUser() { val user: User = User() every { userRepository.exists(any()) } returns true every { paymentGateway.pay(any()) } returns true assertTrue(paymentService.process(user, PaymentDetails())) } } Repository - Kotlin
  22. Mocks, stubs, fake, spies https://blog.cleancoder.com/uncle-bob/2014/05/14/TheLittleMocker.html

  23. DUMMIES You pass in something, and you don’t care who

    it is used, often the object is not used at all. STUB Opposed to dummies, stubs are objects created in a way that you do care how they are used. For example, to tricky an authorization to test if the user ca/can’t do certain actions in the system. SPIES To assert that a method was called by the system under test, as the post by [1]: “You can use Spies to see inside the workings of the algorithms you are testing”. True mocks, stubs, dummies, spies, fakes TRUE MOCKS Is interested in the behavior, instead of return of functions. It cares about which functions were invoked, with what arguments and how often. FAKES Fakes have business logic, so it can drive the system under test with different sets of data.
  24. DUMMIES You pass in something, and you don’t care who

    it is used, often the object is not used at all. STUB Opposed to dummies, stubs are objects created in a way that you do care how they are used. For example, to tricky an authorization to test if the user ca/can’t do certain actions in the system. SPIES To assert that a method was called by the system under test, as the post by [1]: “You can use Spies to see inside the workings of the algorithms you are testing”. True mocks, stubs, dummies, spies, fakes TRUE MOCKS Is interested in the behavior, instead of return of functions. It cares about which functions were invoked, with what arguments and how often. FAKES Fakes have business logic, so it can drive the system under test with different sets of data.
  25. DUMMIES You pass in something, and you don’t care who

    it is used, often the object is not used at all. STUB Opposed to dummies, stubs are objects created in a way that you do care how they are used. For example, to tricky an authorization to test if the user can/can’t do certain actions in the system. SPIES To assert that a method was called by the system under test, as the post by [1]: “You can use Spies to see inside the workings of the algorithms you are testing”. True mocks, stubs, dummies, spies, fakes TRUE MOCKS Is interested in the behavior, instead of return of functions. It cares about which functions were invoked, with what arguments and how often. FAKES Fakes have business logic, so it can drive the system under test with different sets of data.
  26. DUMMIES You pass in something, and you don’t care who

    it is used, often the object is not used at all. STUB Opposed to dummies, stubs are objects created in a way that you do care how they are used. For example, to tricky an authorization to test if the user ca/can’t do certain actions in the system. SPIES To assert that a method was called by the system under test, as the post by [1]: “You can use Spies to see inside the workings of the algorithms you are testing”. True mocks, stubs, dummies, spies, fakes TRUE MOCKS Is interested in the behavior, instead of return of functions. It cares about which functions were invoked, with what arguments and how often. FAKES Fakes have business logic, so it can drive the system under test with different sets of data.
  27. DUMMIES You pass in something, and you don’t care who

    it is used, often the object is not used at all. STUB Opposed to dummies, stubs are objects created in a way that you do care how they are used. For example, to tricky an authorization to test if the user ca/can’t do certain actions in the system. SPIES To assert that a method was called by the system under test, as the post by [1]: “You can use Spies to see inside the workings of the algorithms you are testing”. True mocks, stubs, dummies, spies, fakes TRUE MOCKS Is interested in the behavior, instead of return of functions. It cares about which functions were invoked, with what arguments and how often. FAKES Fakes have business logic, so it can drive the system under test with different sets of data.
  28. DUMMIES You pass in something, and you don’t care who

    it is used, often the object is not used at all. STUB Opposed to dummies, stubs are objects created in a way that you do care how they are used. For example, to tricky an authorization to test if the user ca/can’t do certain actions in the system. SPIES To assert that a method was called by the system under test, as the post by [1]: “You can use Spies to see inside the workings of the algorithms you are testing”. True mocks, stubs, dummies, spies, fakes TRUE MOCKS Is interested in the behavior, instead of return of functions. It cares about which functions were invoked, with what arguments and how often. FAKES Fakes have business logic, so it can drive the system under test with different sets of data.
  29. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  30. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  31. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  32. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  33. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  34. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  35. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  36. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  37. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  38. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createDummie(FileRepository::class); $repository =

    $this->createDummie(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  39. public function test_should_generate_new_version() { $file = new File('1', 'myfile.json', 'src/myfile.json',

    '{}'); $fileRepository = $this->createStub(FileRepository::class); $fileRepository->method('findFile') ->willReturn( $file ); $branch = 'master'; $filesToReleaseRepository = $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly($this->findVersion, $fileRepository, $branch, $filesToReleaseRepository); $assembler->setFilesToWriteRelease([$file]); Stub - PHP
  40. public function test_should_generate_new_version() { $file = new File('1', 'myfile.json', 'src/myfile.json',

    '{}'); $fileRepository = $this->createStub(FileRepository::class); $fileRepository->method('findFile') ->willReturn( $file ); $branch = 'master'; $filesToReleaseRepository = $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly($this->findVersion, $fileRepository, $branch, $filesToReleaseRepository); $assembler->setFilesToWriteRelease([$file]); Stub - PHP
  41. public function test_should_generate_new_version() { $file = new File('1', 'myfile.json', 'src/myfile.json',

    '{}'); $fileRepository = $this->createStub(FileRepository::class); $fileRepository->method('findFile') ->willReturn( $file ); $branch = 'master'; $filesToReleaseRepository = $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly($this->findVersion, $fileRepository, $branch, $filesToReleaseRepository); $assembler->setFilesToWriteRelease([$file]); Stub - PHP
  42. public function test_should_generate_new_version() { $file = new File('1', 'myfile.json', 'src/myfile.json',

    '{}'); $fileRepository = $this->createStub(FileRepository::class); $fileRepository->method('findFile') ->willReturn( $file ); $branch = 'master'; $filesToReleaseRepository = $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly($this->findVersion, $fileRepository, $branch, $filesToReleaseRepository); $assembler->setFilesToWriteRelease([$file]); Stub - PHP
  43. The library and the anti-pattern are different things Mockery !=

    Mockery
  44. • Historic reasons / TDD styles? • As simple as

    the code is, the easiest is to overuse it • Also, no experience in TDD Root cause
  45. 3. The inspector - 🏆9 A unit test that violates

    encapsulation in an effort to achieve 100% code coverage, but knows so much about what is going on in the object that any attempt to refactor will break the existing test and require any change to be reflected in the unit test. Crafting code
  46. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $release = $assembler->packVersion(new Release()); $this->assertEquals('0.0.12', $release->getVersion()); } Getters and setters - PHP
  47. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $release = $assembler->packVersion(new Release()); $this->assertEquals('0.0.12', $release->getVersion()); } Getters and setters - PHP
  48. public function test_should_throw_error_if_no_files_are_found_to_release() { $this->expectException(NoFilesToRelease::class); $fileRepository = $this->createStub(FileRepository::class); $repository =

    $this->createStub(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $release = $assembler->packVersion(new Release()); $this->assertEquals('0.0.12', $release->getVersion()); } Getters and setters - PHP
  49. None
  50. None
  51. package com.mypackage class EmployeeUnitTest { private var company: Company =

    CompanyBuilder.build() init { FieldUtils.writeField(company, "id", CompanyId.randomId(), true) } } Reflection- Kotlin
  52. package com.mypackage class EmployeeUnitTest { private var company: Company =

    CompanyBuilder.build() init { FieldUtils.writeField(company, "id", CompanyId.randomId(), true) } } Reflection- Kotlin
  53. package com.mypackage class EmployeeUnitTest { private var company: Company =

    CompanyBuilder.build() init { FieldUtils.writeField(company, "id", CompanyId.randomId(), true) } } Reflection- Kotlin
  54. public void testSquare() { Class classToTest = SomeApplicationClass.class; Method privateMethod

    = classToTest.getMethod( "computeSquare", new Class[]{Integer.class} ); String result = (String) privateMethod.invoke( new Integer(3) ); assertEquals("9", result); } Reflection - Java
  55. public void testSquare() { Class classToTest = SomeApplicationClass.class; Method privateMethod

    = classToTest.getMethod( "computeSquare", new Class[]{Integer.class} ); String result = (String) privateMethod.invoke( new Integer(3) ); assertEquals("9", result); } Reflection - Java
  56. public void testSquare() { Class classToTest = SomeApplicationClass.class; Method privateMethod

    = classToTest.getMethod( "computeSquare", new Class[]{Integer.class} ); String result = (String) privateMethod.invoke( new Integer(3) ); assertEquals("9", result); } Reflection - Java
  57. public void testSquare() { Class classToTest = SomeApplicationClass.class; Method privateMethod

    = classToTest.getMethod( "computeSquare", new Class[]{Integer.class} ); String result = (String) privateMethod.invoke( new Integer(3) ); assertEquals("9", result); } Reflection - Java
  58. public void testSquare() { Class classToTest = SomeApplicationClass.class; Method privateMethod

    = classToTest.getMethod( "computeSquare", new Class[]{Integer.class} ); String result = (String) privateMethod.invoke( new Integer(3) ); assertEquals("9", result); } Reflection - Java
  59. • Reflection - Encapsulation • Did I hear coverage? Points

    of attention
  60. • Lack of practice on TDD • Oriented to coverage

    Root cause
  61. 4. Generous Leftovers - 🏆5 An instance where one unit

    test creates data that is persisted somewhere, and another test reuses the data for its own devious purposes. If the “generator” is ran afterward, or not at all, the test using that data will outright fail. Crafting code
  62. None
  63. None
  64. const mockFn = jest.fn(); function fnUnderTest(args1) { mockFn(args1); } test('Testing

    once', () => { fnUnderTest('first-call'); expect(mockFn).toHaveBeenCalledWith('first-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); test('Testing twice', () => { fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); Jest - Javascript
  65. const mockFn = jest.fn(); function fnUnderTest(args1) { mockFn(args1); } test('Testing

    once', () => { fnUnderTest('first-call'); expect(mockFn).toHaveBeenCalledWith('first-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); test('Testing twice', () => { fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); Jest - Javascript
  66. const mockFn = jest.fn(); function fnUnderTest(args1) { mockFn(args1); } test('Testing

    once', () => { fnUnderTest('first-call'); expect(mockFn).toHaveBeenCalledWith('first-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); test('Testing twice', () => { fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); Jest - Javascript
  67. const mockFn = jest.fn(); function fnUnderTest(args1) { mockFn(args1); } test('Testing

    once', () => { fnUnderTest('first-call'); expect(mockFn).toHaveBeenCalledWith('first-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); test('Testing twice', () => { fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); Jest - Javascript
  68. const mockFn = jest.fn(); function fnUnderTest(args1) { mockFn(args1); } test('Testing

    once', () => { fnUnderTest('first-call'); expect(mockFn).toHaveBeenCalledWith('first-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); test('Testing twice', () => { fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); Jest - Javascript
  69. const mockFn = jest.fn(); function fnUnderTest(args1) { mockFn(args1); } test('Testing

    once', () => { fnUnderTest('first-call'); expect(mockFn).toHaveBeenCalledWith('first-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); test('Testing twice', () => { fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); Jest - Javascript ✅ ❌
  70. test('Testing twice', () => { mockFn.mockClear(); fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); });

    Jest - Javascript
  71. test('Testing twice', () => { mockFn.mockClear(); fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); });

    Jest - Javascript
  72. const mockFn = jest.fn(); function fnUnderTest(args1) { mockFn(args1); } test('Testing

    once', () => { fnUnderTest('first-call'); expect(mockFn).toHaveBeenCalledWith('first-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); test('Testing twice', () => { mockFn.mockClear(); fnUnderTest('second-call'); expect(mockFn).toHaveBeenCalledWith('second-call'); expect(mockFn).toHaveBeenCalledTimes(1); }); Jest - Javascript ✅ ✅
  73. • Persistent fixtures can become a source of errors •

    Your tests are coupled on a specific sequence to be executed • Persistent fixtures can make test slower Points of attention
  74. • Lack of practice on TDD • Mixing different types

    of tests, integration/unit/end-to-end Root cause
  75. 5. The local hero - 🏆7 A test case that

    is dependent on something specific to the development environment it was written on in order to run. The result is the test passes on development boxes, but fails when someone attempts to run it elsewhere. Crafting code
  76. None
  77. import { Component } from 'react'; import Button from '../../buttons/primary/Primary';

    import '../../../../scss/shake-horizontal.scss'; import './survey.scss'; const config = { surveyUrl: process.env.REACT_APP_SURVEY_URL || '', } const survey = config.surveyUrl; const mapStateToProps = state => ({ user: state.userReducer.user, }); export class Survey extends Component { Javascript - ReactJs
  78. import { Component } from 'react'; import Button from '../../buttons/primary/Primary';

    import '../../../../scss/shake-horizontal.scss'; import './survey.scss'; const config = { surveyUrl: process.env.REACT_APP_SURVEY_URL || '', } const survey = config.surveyUrl; const mapStateToProps = state => ({ user: state.userReducer.user, }); export class Survey extends Component { Javascript - ReactJs
  79. import { Component } from 'react'; import Button from '../../buttons/primary/Primary';

    import '../../../../scss/shake-horizontal.scss'; import './survey.scss'; const config = { surveyUrl: process.env.REACT_APP_SURVEY_URL || '', } const survey = config.surveyUrl; const mapStateToProps = state => ({ user: state.userReducer.user, }); export class Survey extends Component { Javascript - ReactJs
  80. import { Component } from 'react'; import Button from '../../buttons/primary/Primary';

    import '../../../../scss/shake-horizontal.scss'; import './survey.scss'; const config = { surveyUrl: process.env.REACT_APP_SURVEY_URL || '', } const survey = config.surveyUrl; const mapStateToProps = state => ({ user: state.userReducer.user, }); export class Survey extends Component { Javascript - ReactJs
  81. import { Component } from 'react'; import Button from '../../buttons/primary/Primary';

    import '../../../../scss/shake-horizontal.scss'; import './survey.scss'; const config = { surveyUrl: process.env.REACT_APP_SURVEY_URL || '', } const survey = config.surveyUrl; const mapStateToProps = state => ({ user: state.userReducer.user, }); export class Survey extends Component { Javascript - ReactJs
  82. test('show up button when loading is done and skip prop

    is true', () => { const user = { uid: 'uhiuqwqw-k-woqk-wq--qw' }; const wrapper = mount(<Survey user={user} skip={true} />); wrapper.setState({ loading: false }); expect(wrapper.find(Button).length).toBe(1); }); Javascript - ReactJs
  83. test('show up button when loading is done and skip prop

    is true', () => { const user = { uid: 'uhiuqwqw-k-woqk-wq--qw' }; const wrapper = mount(<Survey user={user} skip={true} />); wrapper.setState({ loading: false }); expect(wrapper.find(Button).length).toBe(1); }); Javascript - ReactJs
  84. test('show up button when loading is done and skip prop

    is true', () => { const user = { uid: 'uhiuqwqw-k-woqk-wq--qw' }; const wrapper = mount(<Survey user={user} skip={true} />); wrapper.setState({ loading: false }); expect(wrapper.find(Button).length).toBe(1); }); Javascript - ReactJs
  85. test('show up button when loading is done and skip prop

    is true', () => { const user = { uid: 'uhiuqwqw-k-woqk-wq--qw' }; const wrapper = mount(<Survey user={user} skip={true} />); wrapper.setState({ loading: false }); expect(wrapper.find(Button).length).toBe(1); }); Javascript - ReactJs
  86. test('show up button when loading is done and skip prop

    is true', () => { const user = { uid: 'uhiuqwqw-k-woqk-wq--qw' }; const wrapper = mount(<Survey user={user} skip={true} />); wrapper.setState({ loading: false }); expect(wrapper.find(Button).length).toBe(1); }); Javascript - ReactJs
  87. test('show up button when loading is done and skip prop

    is true', () => { const user = { uid: 'uhiuqwqw-k-woqk-wq--qw' }; const wrapper = mount(<Survey user={user} skip={true} />); wrapper.setState({ loading: false }); expect(wrapper.find(Button).length).toBe(1); }); Javascript - ReactJs
  88. None
  89. None
  90. None
  91. • File system • Dependencies on the operating system •

    External configuration management Points of attention
  92. 6. Wrapping up We are almost done! Crafting code

  93. • The Mockery • The inspector • The generous leftovers

    • The local hero • and many more! What we covered
  94. https://www.codurance.com/publications/building-testing-culture https://www.codurance.com/publications/tdd-anti-patterns-chapter-1

  95. https://www.codurance.com/publications/building-testing-culture https://www.codurance.com/publications/building-testing-culture

  96. 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
  97. Giulio Perrone Hello there! As you may have guessed, my

    name is Giulio and I work at Codurance as a Software Craftsperson! I enjoy writing katas, discussing algorithms and playing video-games. Codurance Crafting Code