Testing Practices and Principles

Kent C. Dodds

Utah

wife, 4 kids, & a dog

PayPal, Inc.

Please Stand...

if you are able ❤️ ♿️

What this talk is

  • Fundamentals behind tests and testing frameworks

  • Distinctions of different forms of testing

  • Writing unit and integration

  • Test doubles (mocks/stubs/etc.)

  • Use TDD to write new features and to find and fix bugs

  • Core principles of testing to ensure your tests give you the confidence you need

What this talk is not

  • Technology-specific
  • How to configure tools
  • Free of trade-offs
  • Long presentation
  • Covering all forms of testing

Setup

If you can, do it now, even if you've already done it...

git clone https://github.com/kentcdodds/testing-workshop.git

cd testing-workshop

npm run setup --silent

Logistics

Routine

  1. Demos 👨‍💻
  2. Exercises 💪 (pair programming!?)
  3. Elaboration and Feedback Form 📑
  4. ? Bonus 👨‍🎓 👩‍🎓
  5. ? Help others 👩‍🔬 👨‍🔬
  6. ? Make pull requests 🙏

Let's
Get
STARTED!

What kind of bugs are there?

Business Logic 🕷

Security 🕷

Accessibility 🐜

User Interface 🐞

Performance 🐛

Regression 🐞

Internationalization 🕷

Integration 🐜

Scaling 🐛

How do we prevent bugs?

  1. Static Types: Flow / TypeScript
  2. Linting: ESLint
  3. Testing: ??

What kinds of testing can we do?

Unit Testing

Regression Testing

Integration Testing

E2E Testing

Smoke Testing

Usability Testing

i18n Testing

Penetration Testing

User Acceptance Testing

Performance Testing

A/B Testing

a11y Testing

Stress Testing

Fuzz Testing

Static Code Analysis

Unit tests

function sum(a, b) {
  return a + b
}

test('sum adds numbers', () => {
  expect(sum(1, 3)).toBe(4)
})

Integration tests

let api, server

beforeAll(async () => {
  server = await startServer()
  const {port} = server.address()
  api = axios.create({
    baseURL: `http://localhost:${port}/api`
  })
})

afterAll(() => server.close())

beforeEach(() => resetDb())

test('can register a user', async () => {
  const registerData = {username: 'bob', password: 'wiley'}
  const testUser = await api
    .post('auth/register', registerData)
    .then(response => response.data.user)
  expect(testUser.username).toBe(registerData.username)

  const readUserUnauthenticated = await api
    .get(`users/${testUser.id}`)
    .then(response => response.data.user)
  expect(readUserUnauthenticated).toEqual(testUser)
})

End-to-end tests

import {assertRoute} from '../utils'

describe('authentication', () => {
  it('should allow users to register', () => {
    const user = {username: 'bob', password: 'wiley'}
    cy
      .visitApp()
      .getByText('Register')
      .click()
      .getByLabelText('Username')
      .type(user.username)
      .getByLabelText('Password')
      .type(user.password)
      .getByText('Login')
      .click()

    cy.url().should('equal', 'http://localhost:3000/')
    cy.getByTestId('username-display').should('contain', user.username)
  })
})

🚗 Test Driven Development 🏎

Red

Green

Refactor

🐛 Fixing Bugs 🐜

Bug

Find Code

Write Test

Fix Test

The Testing Trophy

¢heap

💰🤑💰

🏎💨

🐢

Simple problems 👌

Big problems 😖

Resources

 

My blog/newsletter has a lot of content about testing too: blog.kentcdodds.com

Thank you!