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

TDD anti-patterns

Ed39ca0d44a6e6cdefc76ac548de5f41?s=47 Marabesi
August 26, 2021

TDD anti-patterns

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 TDD anti-patterns, a list inspired by James Carr. From his list, those are the ones I consider the most popular anti-patterns: The liar, Excessive setup, The giant, The Slow Poke (The last one is one of my favorites, is it a pokemon?), beside those the list goes on and we will cover a few more.

TDD anti-patterns is a list to keep our test suite sharp and avoid those mistakes to keep it running fast and maintainable.

Remember, keep it fast, execute it often and keep testing!

Ed39ca0d44a6e6cdefc76ac548de5f41?s=128

Marabesi

August 26, 2021
Tweet

More Decks by Marabesi

Other Decks in Programming

Transcript

  1. ANTI-PATTERNS TDD

  2. Hello there, you can call me Marabesi But my name

    is, Matheus Marabesi Software craftsperson at Codurance The Software Craftsman TDD, XP, Design Patterns e Testable @MatheusMarabesi 🐦 marabesi.com 💻
  3. Agenda 📖 1. Background 2. The liar 3. Excessive setup

    4. The giant 5. The slow poke 6. Wrapping up
  4. 1. Background

  5. T.D.D

  6. None
  7. When Test Driven Development Goes Wrong Dave Farley - By

    Continuous Delivery When Test Driven Development Goes Wrong When Test Driven Development Goes Wrong
  8. 22 The Liar - The Giant - - - -

    - - - - - - Excessive Setup - - - - - - - - - - The Slow Poke The Mockery The Inspector Generous Leftovers The Local Hero The Nitpicker The Secret Catcher The Dodger The Loudmouth The Greedy Catcher The Sequencer Hidden Dependency The Enumerator The Stranger The Operating System Evangelist Success Against All Odds The Free Ride The One The Peeping Tom James Carr - TDD Anti-Patterns
  9. None
  10. 2. The liar An entire unit test that passes all

    of the test cases it has and appears valid, but upon closer inspection it is discovered that it doesn’t really test the intended target at all.
  11. test('the data is peanut butter', () => { function callback(data)

    { expect(data).toBe('peanut butter'); } fetchData(callback); }); 1 2 3 4 5 6 7 function callback(data) { expect(data).toBe('peanut butter'); } test('the data is peanut butter', () => { 1 2 3 4 5 fetchData(callback); 6 }); 7 fetchData(callback); test('the data is peanut butter', () => { 1 function callback(data) { 2 expect(data).toBe('peanut butter'); 3 } 4 5 6 }); 7 test('the data is peanut butter', () => { function callback(data) { expect(data).toBe('peanut butter'); } fetchData(callback); }); 1 2 3 4 5 6 7 Jest docs - Callbacks
  12. test('the data is peanut butter', done => { function callback(data)

    { try { expect(data).toBe('peanut butter'); done(); } catch (error) { done(error); } } fetchData(callback); }); 1 2 3 4 5 6 7 8 9 10 11 12 test('the data is peanut butter', done => { 1 function callback(data) { 2 try { 3 expect(data).toBe('peanut butter'); 4 done(); 5 } catch (error) { 6 done(error); 7 } 8 } 9 10 fetchData(callback); 11 }); 12 expect(data).toBe('peanut butter'); done(); test('the data is peanut butter', done => { 1 function callback(data) { 2 try { 3 4 5 } catch (error) { 6 done(error); 7 } 8 } 9 10 fetchData(callback); 11 }); 12 done(error); test('the data is peanut butter', done => { 1 function callback(data) { 2 try { 3 expect(data).toBe('peanut butter'); 4 done(); 5 } catch (error) { 6 7 } 8 } 9 10 fetchData(callback); 11 }); 12 Jest docs - Callbacks
  13. Wow, async - watch out! Test without assertions

  14. Root cause 1. Lack of practice on TDD 2. Oriented

    to coverage ‼
  15. 3. Excessive setup A test that requires a lot of

    work setting up in order to even begin testing. Sometimes several hundred lines of code is used to setup the environment for one test, with several objects involved, which can make it difficult to really ascertain what is tested due to the “noise” of all of the setup going on.
  16. None
  17. import path from 'path' import compression from 'compression' import connect

    from 'connect' import consola from 'consola' import serveStatic from 'serve-static' import servePlaceholder from 'serve-placeholder' import launchMiddleware from 'launch-editor-middleware' import { determineGlobals, isUrl } from '@nuxt/utils' import { VueRenderer } from '@nuxt/vue-renderer' import Server from '../src/server' import Listener from '../src/listener' import ServerContext from '../src/context' import renderAndGetWindow from '../src/jsdom' import nuxtMiddleware from '../src/middleware/nuxt' import errorMiddleware from '../src/middleware/error' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 import path from 'path' 1 import compression from 'compression' 2 import connect from 'connect' 3 import consola from 'consola' 4 import serveStatic from 'serve-static' 5 import servePlaceholder from 'serve-placeholder' 6 import launchMiddleware from 'launch-editor-middleware' 7 import { determineGlobals, isUrl } from '@nuxt/utils' 8 import { VueRenderer } from '@nuxt/vue-renderer' 9 10 import Server from '../src/server' 11 import Listener from '../src/listener' 12 import ServerContext from '../src/context' 13 import renderAndGetWindow from '../src/jsdom' 14 import nuxtMiddleware from '../src/middleware/nuxt' 15 import errorMiddleware from '../src/middleware/error' 16 Nuxt.js server
  18. None
  19. import { Component } from 'react'; import PropTypes from 'prop-types';

    import { Redirect } from 'react-router'; import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter import { track } from '../../../../packages/emitter/Tracking'; import { auth } from '../../../../pages/login/Auth'; import Reason from '../../../../packages/engine/Reason'; import EditorManager from '../editor-manager/EditorManager'; import Guide from '../guide/Guide'; import Intro from '../intro/Intro'; import DebugButton from '../../buttons/debug/Debug'; import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; import {executeTestCase} from '../../../../packages/engine/Tester'; const Wrapped = ( code, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const Wrapped = ( code, import { Component } from 'react'; 1 import PropTypes from 'prop-types'; 2 import { Redirect } from 'react-router'; 3 import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter 4 import { track } from '../../../../packages/emitter/Tracking'; 5 import { auth } from '../../../../pages/login/Auth'; 6 import Reason from '../../../../packages/engine/Reason'; 7 import EditorManager from '../editor-manager/EditorManager'; 8 import Guide from '../guide/Guide'; 9 import Intro from '../intro/Intro'; 10 import DebugButton from '../../buttons/debug/Debug'; 11 import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; 12 import {executeTestCase} from '../../../../packages/engine/Tester'; 13 14 15 16 code, import { Component } from 'react'; 1 import PropTypes from 'prop-types'; 2 import { Redirect } from 'react-router'; 3 import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter 4 import { track } from '../../../../packages/emitter/Tracking'; 5 import { auth } from '../../../../pages/login/Auth'; 6 import Reason from '../../../../packages/engine/Reason'; 7 import EditorManager from '../editor-manager/EditorManager'; 8 import Guide from '../guide/Guide'; 9 import Intro from '../intro/Intro'; 10 import DebugButton from '../../buttons/debug/Debug'; 11 import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; 12 import {executeTestCase} from '../../../../packages/engine/Tester'; 13 14 const Wrapped = ( 15 16 import { Component } from 'react'; 1 import PropTypes from 'prop-types'; 2 import { Redirect } from 'react-router'; 3 import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter 4 import { track } from '../../../../packages/emitter/Tracking'; 5 import { auth } from '../../../../pages/login/Auth'; 6 import Reason from '../../../../packages/engine/Reason'; 7 import EditorManager from '../editor-manager/EditorManager'; 8 import Guide from '../guide/Guide'; 9 import Intro from '../intro/Intro'; 10 import DebugButton from '../../buttons/debug/Debug'; 11 import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; 12 import {executeTestCase} from '../../../../packages/engine/Tester'; 13 14 const Wrapped = ( 15 code, 16 import { Component } from 'react'; 1 import PropTypes from 'prop-types'; 2 import { Redirect } from 'react-router'; 3 import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter 4 import { track } from '../../../../packages/emitter/Tracking'; 5 import { auth } from '../../../../pages/login/Auth'; 6 import Reason from '../../../../packages/engine/Reason'; 7 import EditorManager from '../editor-manager/EditorManager'; 8 import Guide from '../guide/Guide'; 9 import Intro from '../intro/Intro'; 10 import DebugButton from '../../buttons/debug/Debug'; 11 import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; 12 import {executeTestCase} from '../../../../packages/engine/Tester'; 13 14 const Wrapped = ( 15 code, 16 import { Component } from 'react'; 1 import PropTypes from 'prop-types'; 2 import { Redirect } from 'react-router'; 3 import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter 4 import { track } from '../../../../packages/emitter/Tracking'; 5 import { auth } from '../../../../pages/login/Auth'; 6 import Reason from '../../../../packages/engine/Reason'; 7 import EditorManager from '../editor-manager/EditorManager'; 8 import Guide from '../guide/Guide'; 9 import Intro from '../intro/Intro'; 10 import DebugButton from '../../buttons/debug/Debug'; 11 import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; 12 import {executeTestCase} from '../../../../packages/engine/Tester'; 13 14 const Wrapped = ( 15 code, 16 import { Component } from 'react'; 1 import PropTypes from 'prop-types'; 2 import { Redirect } from 'react-router'; 3 import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter 4 import { track } from '../../../../packages/emitter/Tracking'; 5 import { auth } from '../../../../pages/login/Auth'; 6 import Reason from '../../../../packages/engine/Reason'; 7 import EditorManager from '../editor-manager/EditorManager'; 8 import Guide from '../guide/Guide'; 9 import Intro from '../intro/Intro'; 10 import DebugButton from '../../buttons/debug/Debug'; 11 import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; 12 import {executeTestCase} from '../../../../packages/engine/Tester'; 13 14 const Wrapped = ( 15 code, 16 import { Component } from 'react'; 1 import PropTypes from 'prop-types'; 2 import { Redirect } from 'react-router'; 3 import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter 4 import { track } from '../../../../packages/emitter/Tracking'; 5 import { auth } from '../../../../pages/login/Auth'; 6 import Reason from '../../../../packages/engine/Reason'; 7 import EditorManager from '../editor-manager/EditorManager'; 8 import Guide from '../guide/Guide'; 9 import Intro from '../intro/Intro'; 10 import DebugButton from '../../buttons/debug/Debug'; 11 import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; 12 import {executeTestCase} from '../../../../packages/engine/Tester'; 13 14 const Wrapped = ( 15 code, 16 import { Component } from 'react'; 1 import PropTypes from 'prop-types'; 2 import { Redirect } from 'react-router'; 3 import Emitter, { PROGRESS_UP, LEVEL_UP } from '../../../../packages/emitter/Emitter 4 import { track } from '../../../../packages/emitter/Tracking'; 5 import { auth } from '../../../../pages/login/Auth'; 6 import Reason from '../../../../packages/engine/Reason'; 7 import EditorManager from '../editor-manager/EditorManager'; 8 import Guide from '../guide/Guide'; 9 import Intro from '../intro/Intro'; 10 import DebugButton from '../../buttons/debug/Debug'; 11 import {SOURCE_CODE, TEST_CODE} from '../editor-manager/constants'; 12 import {executeTestCase} from '../../../../packages/engine/Tester'; 13 14 const Wrapped = ( 15 code, 16 Testable test case matchers
  20. None
  21. /** * Makes sure the use of "localhost" in the

    Hudson URL reports a warning. */ @Test public void localhostWarning() throws Exception { HtmlPage p = j.createWebClient().goTo("configure"); HtmlInput url = p.getFormByName("config").getInputByName("_.url"); url.setValueAttribute("http://localhost:1234/"); assertThat(p.getDocumentElement().getTextContent(), containsString("instead of l } 1 2 3 4 5 6 7 8 9 10 HtmlPage p = j.createWebClient().goTo("configure"); /** 1 * Makes sure the use of "localhost" in the Hudson URL reports a warning. 2 */ 3 @Test 4 public void localhostWarning() throws Exception { 5 6 HtmlInput url = p.getFormByName("config").getInputByName("_.url"); 7 url.setValueAttribute("http://localhost:1234/"); 8 assertThat(p.getDocumentElement().getTextContent(), containsString("instead of l 9 } 10 HtmlInput url = p.getFormByName("config").getInputByName("_.url"); /** 1 * Makes sure the use of "localhost" in the Hudson URL reports a warning. 2 */ 3 @Test 4 public void localhostWarning() throws Exception { 5 HtmlPage p = j.createWebClient().goTo("configure"); 6 7 url.setValueAttribute("http://localhost:1234/"); 8 assertThat(p.getDocumentElement().getTextContent(), containsString("instead of l 9 } 10 url.setValueAttribute("http://localhost:1234/"); /** 1 * Makes sure the use of "localhost" in the Hudson URL reports a warning. 2 */ 3 @Test 4 public void localhostWarning() throws Exception { 5 HtmlPage p = j.createWebClient().goTo("configure"); 6 HtmlInput url = p.getFormByName("config").getInputByName("_.url"); 7 8 assertThat(p.getDocumentElement().getTextContent(), containsString("instead of l 9 } 10 assertThat(p.getDocumentElement().getTextContent(), containsString("instead of l /** 1 * Makes sure the use of "localhost" in the Hudson URL reports a warning. 2 */ 3 @Test 4 public void localhostWarning() throws Exception { 5 HtmlPage p = j.createWebClient().goTo("configure"); 6 HtmlInput url = p.getFormByName("config").getInputByName("_.url"); 7 url.setValueAttribute("http://localhost:1234/"); 8 9 } 10 Jenkins configuration location
  22. Root cause 1. Adding tests after the source code 2.

    Lack of SOLID principes
  23. 4. The giant A unit test that, although it is

    validly testing the object under test, can span thousands of lines and contain many many test cases. This can be an indicator that the system under tests is a God Object.
  24. namespace Sped\Gnre\Sefaz; use Sped\Gnre\Sefaz\LoteGnre; use Sped\Gnre\Sefaz\EstadoFactory; class Lote extends LoteGnre

    { private $estadoFactory; private $ambienteDeTeste = false; public function getEstadoFactory() {...} public function setEstadoFactory(EstadoFactory $estadoFactory) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public function getEstadoFactory() {...} public function setEstadoFactory(EstadoFactory $estadoFactory) namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 13 14 15 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 namespace Sped\Gnre\Sefaz; 1 2 use Sped\Gnre\Sefaz\LoteGnre; 3 use Sped\Gnre\Sefaz\EstadoFactory; 4 5 class Lote extends LoteGnre 6 { 7 8 private $estadoFactory; 9 10 private $ambienteDeTeste = false; 11 12 public function getEstadoFactory() 13 {...} 14 15 public function setEstadoFactory(EstadoFactory $estadoFactory) 16 sped GNRE
  25. Root cause 1. Test after, instead of test first 2.

    Lack of SOLID principes 3. Coupled with the XML lib
  26. 5. The Slow Poke A unit test that runs incredibly

    slow. When developers kick it off, they have time to go to the bathroom, grab a smoke, or worse, kick the test off before they go home at the end of the day.
  27. via GIPHY

  28. Eradicating Non-Determinism in Tests - Asynchronous Behavior Martin Fowler, 2011

  29. test('should show Buggy on user interaction by keyboard', done =>

    { const wrapper = mount( <Guide guideContent={content} currentHint={0} showNext={false} invalidCode={false} afkExpirationTime={400} /> ); setTimeout(() => { wrapper.update(); expect(wrapper.find('BuggySleepy').length).toBe(1); const keypress = new KeyboardEvent('keydown', {keyCode: 37}); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 setTimeout(() => { wrapper.update(); expect(wrapper.find('BuggySleepy').length).toBe(1); const keypress = new KeyboardEvent('keydown', {keyCode: 37}); test('should show Buggy on user interaction by keyboard', done => { 1 const wrapper = mount( 2 <Guide 3 guideContent={content} 4 currentHint={0} 5 showNext={false} 6 invalidCode={false} 7 afkExpirationTime={400} 8 /> 9 ); 10 11 12 13 14 15 16 test('should show Buggy on user interaction by keyboard', done => { 1 const wrapper = mount( 2 <Guide 3 guideContent={content} 4 currentHint={0} 5 showNext={false} 6 invalidCode={false} 7 afkExpirationTime={400} 8 /> 9 ); 10 11 setTimeout(() => { 12 wrapper.update(); 13 expect(wrapper.find('BuggySleepy').length).toBe(1); 14 15 const keypress = new KeyboardEvent('keydown', {keyCode: 37}); 16 wrapper.update(); expect(wrapper.find('BuggySleepy').length).toBe(1); const keypress = new KeyboardEvent('keydown', {keyCode: 37}); test('should show Buggy on user interaction by keyboard', done => { 1 const wrapper = mount( 2 <Guide 3 guideContent={content} 4 currentHint={0} 5 showNext={false} 6 invalidCode={false} 7 afkExpirationTime={400} 8 /> 9 ); 10 11 setTimeout(() => { 12 13 14 15 16 const keypress = new KeyboardEvent('keydown', {keyCode: 37}); test('should show Buggy on user interaction by keyboard', done => { 1 const wrapper = mount( 2 <Guide 3 guideContent={content} 4 currentHint={0} 5 showNext={false} 6 invalidCode={false} 7 afkExpirationTime={400} 8 /> 9 ); 10 11 setTimeout(() => { 12 wrapper.update(); 13 expect(wrapper.find('BuggySleepy').length).toBe(1); 14 15 16
  30. CRON jobs Leap year / any time related

  31. I can also relate this pattern to the following issues:

    1. Focus more on integration test instead of unit, this can lead to slow suites. This is also a side effect of focusing too munch on coverage instead of side effect.
  32. None
  33. 2. Trying to reverse engineer the TDD flow. it often

    happens when there is no tests on the code and as soon as developers start to add them, it hits the point 1 back.
  34. Testing is Good. Pyramids are Bad. Ice Cream Cones are

    the Worst - Stephen H Fishman
  35. 6. Wrapping up

  36. The liar Excessive setup The giant The slow poke and

    many more!
  37. Most of the anti-patterns presented are related to test last

  38. If its hard to test, take a step back.

  39. Working skeleton Growing object oriented software, guided by tests -

    Steve Freeman and Nat Pryce
  40. Happy testing 🤪

  41. Hello there, you can call me Marabesi But my name

    is, Matheus Marabesi Software craftsperson at TDD, XP, Design Patterns and Codurance The Software Craftsman Testable @MatheusMarabesi 🐦 marabesi.com 💻