Skip to content

Instantly share code, notes, and snippets.

@luishrd
Last active July 9, 2018 06:20
Show Gist options
  • Save luishrd/38c373b33e5f59b28947295905c0efe6 to your computer and use it in GitHub Desktop.
Save luishrd/38c373b33e5f59b28947295905c0efe6 to your computer and use it in GitHub Desktop.
CS10 - Testing

(Automated) Testing

Day 1

  • why?
  • how?
  • what? comes from experience and the system we're testing and even the tech stack.
  • when? test-first vs test after.

Why learn it?

  • good for resume.
  • can work on QA and DevOps.
  • helps understand how an application works.

Why test?

  • Verifying correctness.
  • Confidence (in the sense of trusting your code).
  • Safety net.
  • Prevents regressions.
  • What could happen if I have no tests.
    • test manually, as the app grows, the time needed will not scale.
    • regressions, code that used to work breaks.
    • you just don't know if the code is correct for all cases, including edge/corner cases.
    • adding new features becomes slow.
    • angry customers => product fail.

How?

  • We write code to test our code.
  • Tooling: Test runner (Mocha, Jasmine, Jest, QUnit) + assertion library (Chai, Assert, Jest, Jasmine).
  • We are using Jest for everything.

Automated Test Types

  • unit tests. Fastest.
  • integration tests. why it is important. Other Examples
  • end to end. Slow.
  • component testing. (for component based frameworks, like React, Angular, Vue, etc.)
  • snapshot testing. (unique to our stack/tools)
  • coverage testing.
  • functional testing.
  • performance testing.
  • aceptance testing.

Unit Tests

  • fast.
  • simple to write and execute.
  • used to test correctness.
  • written by developers.
  • the tool for doing TDD/BDD.

Component Tests

  • appearance and functionality of a component.
  • highly sensitive to small changes.
  • great against regression.
  • verifies changes to component output resulting from changest to state.
  • does not verify interaction between components.

Snapshot Tests

  • automatically generated by Jest.
  • sub-type of component testing.
  • checks current output against prior output.
  • fails with any change to the component.
  • very good to detect regressions.

We will cover

  • unit.
  • component.
  • snapshot.
  • integration.

Jest

  • a test runner + cli in npm package.
  • made by Facebook and included out of the box with create-react-app.
  • general purpose, but works very well with React applications.
  • recommended by the React team.
  • can:
    • run tests (mocha too)
    • asynchronous code testing (mocha too).
    • spies included.
    • snapshot testing.
    • module mocking.
  • includes coverage reports

Jest Installation

  • installed globally.
  • installed locally.
  • if NOT used with a CI (Continous Integration) server, install it as a devDependency.

Running Jest

  • configure npm scripts.
  • on development run it in watch mode.

Running Tests

  • any file inside a __tests__ folder will be run automatically.
  • any file that ends in .spec.js or .test.js will also be executed automatically.

Tests inside __tests__

  • easy to find.
  • unrelated files together.
  • easy to isolate a particular set of tests.
  • files can be named anything.

Colocated

  • always adjacent to the files the apply to.
  • unrelated files are less likely to share a folder.
  • need to follow the naming convention.

Jest Globals

  • the it global is a method you pass a function to, that function is executed as a block of tests by the test runner.
  • the describe is optional for grouping a number of related it statements. This is also known as a suite.

Watch Mode

  • instead of running the tests manually use watch mode.
  • tests run automatically as files change.
  • only tests pertaining to changed files run.
  • Jest detects changes automatically.
  • change the npm test script to: jest --watch.
  • changing the code or the tests will re-run the tests.
  • using ctrl + c will stop the test runner/watcher.

Jest Matchers (assertions or expectations)

Documentation on Matchers.

Some commonly used (and useful) matchers.

  • toBe: that two values are equivalent using strict equality (checks reference/identity).
  • toEqual: that two values are equivalent by looking at the values (if walks like a duck, it's a duck). For two different arrays with the same values, toBe fails and toEqual succeeds.
  • toContain: checks that a value exists in an array.
  • toHaveLength: checks the lenght of an array. Like toContain, it is more readable than using toEqual and toBe combined with array methods.
  • not: reverses the assertion.

Day 2

Review

  • can we install Jest globally?
  • can Jest tests be run as part of the build and deployment processes?
  • why is watch mode convenient? how can we "turn it on" when running our tests?

characteristics of unit tests

  • fast.
  • simple to write and execute.
  • used to test correctness.
  • written by developers.
  • the tool for doing TDD/BDD.

Today

  • drawbacks of testing.
  • more about Jest.
  • setup and teardown globals.
  • skipping and isolating tests.
  • testing asynchronous operations.

Drawbacks of Testing

  • more code to write, and maintain.
  • more tooling.
  • additional dependencies.
  • may provide a false sense of security.
  • trivial test failures may break the build.

More about Jest

  • a test runner + cli in npm package.
  • made by Facebook and included out of the box with create-react-app.
  • general purpose, but works very well with React applications.
  • recommended by the React team.
  • can:
    • run tests (mocha too)
    • asynchronous code testing (mocha too).
    • spies included.
    • snapshot testing.
    • module mocking.
  • includes coverage reports

Setup and Teardown Globals

  • exist in the global scope like describe and it.
  • beforeAll: runs once before the first test.
  • beforeEach: runs before the tests, good for setup code. // test runs
  • afterEach: runs after the tests, good for clean up.
  • afterAll: runs once after the last test.
  • setup and tear down vs factory pattern.

Skipping and Isolating Tests

  • skipping tests: it.skip()
  • isolating is used to pick the tests you want to run: it.only()
  • it also works at the test suite level: describe.only() or describe.skip()

Testing Asynchoronous Code

  • does not complete right away.
  • Jest must be notified that the test completed.
  • techiques:
    • invoke a done() callback that is passed to the test.
    • return a promise from a test.
    • pass an async function to it. Not supported everywhere yet.
const helpers = require('./project-1');
// start testing!
describe.skip('project-1', () => {
describe('multiplyByTen', () => {
it('returns NaN when given a non numeric value', () => {
expect(helpers.multiplyByTen(undefined)).toBeNaN();
expect(helpers.multiplyByTen('two')).toBeNaN();
});
it('should return the given number multiplied by 10', () => {});
});
});
describe('isEven', () => {
it.only('should return true for even numbers', () => {
expect(helpers.isEven(4)).toBeTruthy();
expect(helpers.isEven(0)).toBeTruthy();
});
it.only('should return false for odd numbers', () => {
expect(helpers.isEven(3)).toBeFalsy();
expect(helpers.isEven(-1)).toBeFalsy();
});
});
// should return the right amount given a numeric value
// another idea
describe.skip('addition helpers', () => {
describe.skip('add', () => {
let expected;
// afterAll(() => {
// console.log('after all');
// });
// beforeAll(function() {
// expected = 42;
// console.log('before all');
// });
// afterEach(() => {
// console.log('after each');
// });
// beforeEach(() => {
// console.log('before each');
// });
it('can add two numbers', function() {
// arrange
var user = makeUser('Xang', 48);
// act
const actual = add(40, 2);
// assert
expect(actual).toEqual(expected);
});
it('can multiply numbers', () => {
// arrange
const expected = 42;
const max = Math.max;
// act
const actual = multiply(21, 2);
// assert
expect(actual).toEqual(expected);
expect(multiply(max, 2)).toBeNaN();
});
});
});
describe('ASYNC OPERATIONS', () => {
it('async with done callback', done => {
setTimeout(done, 2000);
});
it('async with promises', () => {
return new Promise(resolve => setTimeout(resolve, 2000));
});
it('async with promises', async () => {
await new Promise(resolve => setTimeout(resolve, 2000));
});
});
function makeUser(name, age) {
return { name, age };
}
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment