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

TDD anti-patterns

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!

Marabesi

August 26, 2021
Tweet

More Decks by Marabesi

Other Decks in Programming

Transcript

  1. 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 💻
  2. Agenda 📖 1. Background 2. The liar 3. Excessive setup

    4. The giant 5. The slow poke 6. Wrapping up
  3. When Test Driven Development Goes Wrong Dave Farley - By

    Continuous Delivery When Test Driven Development Goes Wrong When Test Driven Development Goes Wrong
  4. 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
  5. 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.
  6. 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
  7. 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
  8. 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.
  9. 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
  10. 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
  11. /** * 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
  12. 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.
  13. 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
  14. Root cause 1. Test after, instead of test first 2.

    Lack of SOLID principes 3. Coupled with the XML lib
  15. 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.
  16. 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
  17. 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.
  18. 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.
  19. 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 💻