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

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

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.

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

    leftovers and The local hero 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 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
  11. 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
  12. 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
  13. 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
  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 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
  17. 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
  18. 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
  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. 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.
  21. 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.
  22. 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.
  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 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.
  26. 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
  27. 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
  28. 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
  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->createDummie(FileRepository::class); $repository =

    $this->createDummie(FilesToReleaseRepository::class); $assembler = new Assembly( $this->findVersion, $fileRepository, 'master', $repository ); $assembler->setFilesToWriteRelease([]); $assembler->packVersion(new Release()); } Stub - PHP
  36. 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
  37. 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
  38. 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
  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. • Historic reasons / TDD styles? • As simple as

    the code is, the easiest is to overuse it • Also, no experience in TDD Root cause
  41. 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
  42. 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
  43. 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
  44. 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
  45. package com.mypackage class EmployeeUnitTest { private var company: Company =

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

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

    CompanyBuilder.build() init { FieldUtils.writeField(company, "id", CompanyId.randomId(), true) } } Reflection- Kotlin
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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
  57. 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
  58. 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
  59. 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 ✅ ❌
  60. 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 ✅ ✅
  61. • 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
  62. • Lack of practice on TDD • Mixing different types

    of tests, integration/unit/end-to-end Root cause
  63. 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
  64. 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
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. • File system • Dependencies on the operating system •

    External configuration management Points of attention
  76. • The Mockery • The inspector • The generous leftovers

    • The local hero • and many more! What we covered
  77. 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
  78. 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