writing tests falls into one of two categories. “Here’s how to test a function that add two numbers. Now you can test anything. Good luck.” “You really should not be mocking your flux capacitor, but instead link the flibitz to the your cross-channel bit splicer.”
bit of functionality you want to add. Write the functional code until the test passes. Refactor both new and old code to make it well structured. - Martin Fowler, “TestDrivenDevelopment”, https://martinfowler.com/bliki/TestDrivenDevelopment.html
avoid a lot of bad designs. It makes you think about the code you need to write, BEFORE you write it. 2. Once you have tests, they help you avoid introducing subtle bugs when you have to change the code later. Existing tests help prevent regressions in your code, where adding or changing one thing accidentally breaks another thing.
new things (YEAH! TESTS!) 3. Velocity slows because TDD does take more time up-front 4. “We’re not going to meet this deadline ?!?” (STOP DOING TDD) 5. As tests age, skip them or ignore failing tests (PEOPLE IGNORE TESTS) Start TDD Deadlines ?!? Graveyard of Tests
tests, you have to wait: first for the entire product to be built, then for it to be deployed, and finally for all end-to-end tests to run. When the tests do run, flaky tests tend to be a fact of life. And even if a test finds a bug, that bug could be anywhere in the product. Although end-to-end tests do a better job of simulating real user scenarios, this advantage quickly becomes outweighed by all the disadvantages of the end-to-end feedback loop. — https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html Unit vs. Functional Tests
passed count of 1', function() { // arrange // set some variable // act // call some function // assert // }); Given a certain value, it always returns the same value
passed count of 1', function() { // arrange var numActiveTodos = 1; var template = new Template(); // … }); An example from our Template module, part 1
passed count of 1', function() { // … // act var counterView = template.itemCounter(numActiveTodos); // … }); An example from our Template module, part 2
passed count of 1', function() { // … // assert expect(counterView).toBe('<strong>1</ strong> item left'); }); An example from our Template module, part 3
passed count of more than 1', function() { var numActiveTodos = 2; var template = new Template(); var counterView = template.itemCounter(numActiveTodos); expect(counterView).toBe('<strong>2</ strong> items left'); }); Testing the other path through the code
passed count of 0', function() { var numActiveTodos = 0; var template = new Template(); var counterView = template.itemCounter(numActiveTodos); expect(counterView).toBe('<strong>0</ strong> items left'); }); Testing an edge case
function() { var storageName = 'shaggy'; var storage = new Store(storageName); var dataStore = JSON.parse(localStorage.getItem(stora geName)); expect(typeof dataStore).toEqual('object'); });
find something else to test Here’s where having a test-driven mindset encourages you to have a more modular architecture. Callbacks/promises Mocking: jest.fn()
status', function() { … var model = new Model(mockStore); var getCountCallback = jest.fn(); model.getCount(getCountCallback); var expectedResult = { active: 2, completed: 1, total: 3 }; expect(getCountCallback).toHaveBeenCall edWith(expectedResult); }); Option 1, Using a mock (continued)
status', function() { var Store = require('../Store/Store.js'); var exampleTodos = [{…}, {…}, {…}]; var realStore = new Store(‘yamato'); exampleTodos.forEach(function(todo) { realStore.save(todo) }); … }); Option 2, Just use the dependency
status', function() { … var model = new Model(realStore); var getCountCallback = jest.fn(); model.getCount(getCountCallback); var expectedResult = { active: 2, completed: 1, total: 3 }; expect(getCountCallback).toHaveBeenCall edWith(expectedResult); }); Option 2, Just use the dependency (continued)
a user of Todos with TDD I want to be able to enter a new todo item So that I can add to my list of things to do Scenario: See the todo input Given I am on the Todos with TDD page When I look for an element with class "new-todo" Then I should see a placeholder of "What needs to be done?" Scenario: Enter a new todo Given I am on the Todos with TDD page When I look for an element with class "new-todo" And I enter text in the input field Then I should see my new item in the Todo list
= require('cucumber'); var assert = require('assert'); defineSupportCode(function({Given, When, Then}) { var todoInput; Given('I am on the Todos with TDD page', function() { return this.driver.get('http://localhost:8080'); }); … todo_input_steps.js (part 1)
testing? Although it is possible to write snapshot files manually, that is usually not approachable. Snapshots help figuring out whether the output of the modules covered by tests is changed, rather than giving guidance to design the code in the first place. — https://facebook.github.io/jest/docs/snapshot-testing.html A Note about Snapshot Testing
to End testing of React apps with Nightwatch”, https://blog.syncano.io/testing-syncano/ “Intern”, https://github.com/theintern/intern (a new framework for managing unit and functional tests, thanks to Jaydeep Parmar, @jaydeep98a, for this reference)