F09: Testing!

End-to-end & Node (Angular senere)

What, why?

  • Core-funksjonalitet er i grunnen ferdig
     
  • Stabilitet!
     
  • Burde ha testet fra begynnelsen av – no time!

Tre typer tester

  • End-to-end testing
     
  • "Unit" testing (Node)
     
  • Unit testing (Angular)

Sidenotat: dev dependencies

  • Egen blokk til bare development
    • Gulp med dependencies
    • Code coverage
    • Testing framework
    • Store binærfiler (Protractor)
    • ...
    • Installeres per default
      • $ npm install --production
{
  "name": "first-end-to-end-project",
  "dependencies": {
    "express": "^4.12.3"
  },
  "devDependencies": {
    "chai": "^2.2.0",
    "mocha": "^2.2.4",
    "protractor": "^2.0.0"
  }
}

End-to-end testing (e2e)

  • Tester hele applikasjonen, fra UI til DB
     
  • Automatisert klikking i interfacet (nettsida)
     
  • Automatiserer workflows
    • "user signs up for an account"
    • "user looks at her previously saved items"
       
  • Tregt som fy, men veldig effektivt til å fange bugs

Toolchain

  • Test runner: Protractor
     
  • Test framework: Mocha
     
  • Assertion framework: Chai
     
  • Browser
    • Execution: Selenium
    • Verification: WebDriver

Protractor

  • Test runner for Angular
     
  • Node.js-applikasjon
    • Kan require-e ting!
       
  • Designet for (men ikke begrenset til) Angular
     
  • Bruker WebDriver og Selenium for å kjøre en browser
     
  • $ npm install --save-dev protractor

Protractor config

Automatisert oppsett av WebDriver med Selenium

$ ./node_modules/.bin/webdriver-manager update

Updating selenium standalone
downloading https://selenium-release.storage.googleapis.com/2.45/selenium-server-standalone-2.45.0.jar...
Updating chromedriver
downloading https://chromedriver.storage.googleapis.com/2.14/chromedriver_mac32.zip...
chromedriver_2.14.zip downloaded to /the-project/node_modules/protractor/selenium/chromedriver_2.14.zip
selenium-server-standalone-2.45.0.jar downloaded to \
    /the-project/node_modules/protractor/selenium/selenium-server-standalone-2.45.0.jar

Protractor er bare en
test runner

  • Testing framework time: Mocha!

Mocha

Flexible testing framework


"Tilsvarer" XUnit (JUnit for Java, NUnit for .NET), XCTest for Swift/Objective-C


Krever litt config (men ikke noe ille)


http://mochajs.org/

Basic Protractor-test

Putt alle tester i project-root/test (konvensjon)

 

Lag et directory for hver type test

 

Første test

describe('making a post', function() {
    it('logs in and creates a new item', function() {
        // go to homepage
        // click 'login'
        // fill out and submit login form
        // submit a new item on the home page
        
        // The new item should be visible as the first item on the page
    });
});

test/e2e/making-an-item.spec.js

  • Protractor beskriver user stories
  • E-commerce:
  1. Enter site,
  2. find a product,
  3. add it to cart,
  4. complete order

Ting å legge merke til

  • Sørger for at applikasjonen er stabil fra brukers perspektiv
    • Fanger bugs som direkte bruker direkte
  • e2e-testing er tregt

     
  • Kan ta lang tid å skrive testene
     
  • For spesifikke tester må endres ofte hvis spec endres (tar lang tid)
     
  • Final assertion: hva skal egentlig testes?
    • Resonner baklengs

Navngiving

  • Vi definerer selv hvilke filer som er tester (protractor.conf.js)
     
  • Kommer til å kalle testene *.spec.js
     
  • Gjør det mulig å ha utility-filer (*.js) blant testene

Protractor-config

  • project-root/protractor.conf.js
exports.config = {
    framework: 'mocha',
    specs: [
        'test/e2e/**/*.spec.js'
    ]
};

Bruk Mocha & kjør tester med navn *.spec.js

(husk $ npm install --save-dev mocha)

En faktisk test

describe('making a post', function() {
    it('logs in and creates a new post', function() {
        // go to homepage
        browser.get('http://localhost:3000');
        // click 'login'
        // fill out and submit login form
        // submit a new post on the posts page
        
        // The new post should be visible as the first post on the page
    });
});

Kjør Protractor igjen

$ ./node_modules/.bin/protractor 

Starting selenium standalone server...
[launcher] Running 1 instances of WebDriver
Selenium standalone server started at http://10.21.24.161:63592/wd/hub

Listening on port 3001
    making a post logs in and creates a new post: Connected to MongoDB!
  ․ making a post logs in and creates a new post: 1289ms

  1 passing (1s)

Shutting down selenium standalone server.
[launcher] 0 instance(s) of WebDriver still running
[launcher] chrome #1 passed

(Samme kommando som før, uten update)

Siden være en faktisk Angular-app

Hva hvis serveren er nede?

Start serveren fra Protractor

exports.config = {
    framework: 'mocha',
    specs: [
        'test/e2e/**/*.spec.js'
    ],
    onPrepare: function() {
        require('./server-node/hello-tests-server.js');
    }
};

Hva hvis den allerede kjører?

Start server på annen port

project root/protractor.conf.js 

project root/server-node/the-server.js

project root/test/e2e/the-test.js

Protractor Locators

// find an element using css selector
by.css('.someclass');

// find an element using id
by.id('someid');

// find an element by ng-model (e.g. username)
by.model('username');

// find an element by binding (e.g., {{currentUser}})
by.binding('currentUser');

// find an element by repeater (e.g., item in items
by.repeater('item in items');

Interager med DOM

// click a button or link
element(by.css('.mybutton')).click();

// fill out a text input
element(by.css('.username-input')).sendKeys('theneva');

NB: Events er asynkrone

Eksempel: Fyll inn et login form

// fill out and submit login form
var usernameInput = element(by.model('username'));
usernameInput.sendKeys('theneva');

var passwordInput = element(by.model('password'));
passwordInput.sendKeys('1234');

// Click the login button
var loginButton = element(by.css('.button-login'));
loginButton.click();

// save a new item on the home page
var nameInput = element(by.model('newItem.name'));
nameInput.sendKeys('Some random item');

var saveButton = element(by.css('.button-save'));
saveButton.click();

Hent ut første items-element

// the new item should be visible as the first item on the page
element.all(by.repeater('item in items')).then(function(items) {
	var firstItem = items[0];
	firstItem.element(by.css('.item-name')).getText().then(function(firstItemName) {
		console.log(firstItemName);
	});

	firstItem.element(by.css('.item-author')).getText().then(function(firstItemAuthor) {
		console.log(firstItemAuthor);
	});
});

Assertion time!

... vent, Mocha har ikke assertions?

Assertion lib/framework: Chai

$ npm install --save-dev chai

var expect = require(’chai ’).expect;

...

firstItem.element(by.css(’.item−name’)).getText().then(function(firstItemName) {           
    expect(firstItemName).to.equal(itemContent);
});

firstItem.element(by.css(’.item−author’)).getText().then(function(firstItemAuthor) {
    expect(firstItemAuthor).to.equal(username);
});

Ex: wrong assertion:

Vi messer med databasen?

  • Vi jobber mot den faktiske databasen
     
  • Mange måter å håndtere dette
    • dev-database med env-variabel (som med port)
       
    • dropp databasen etter hver test (eller når fullført)
      • du er uansett i dev-miljø
      • Protractor afterEach-filter
         
    • Krever planlegging (og kanskje dokumentasjon)

Stacken (igjen)

  • Test runner: Protractor -> WebDriver + Selenium 
     
  • Test framework: Mocha
     
  • Assertion library/framework: Chai

Avsluttende tanker og pekere

  • e2e-testing er (kanskje) den viktigste typen testing
     
  • Tester fra brukers perspektiv
     
  • Fanger bugs som ikke oppdages under utvikling
     
  • Uttrykker requirements (user stories)
     
  • Dokumentasjon? Psh
     
  • Lar applikasjonen holde høy kvalitet

Unit testing

Node "unit" testing

  • Ikke egentlig unit testing
     
  • Treffer databasen i stedet for å mocke
    • Samme problem som tidligere
       
  • Mulig å skrive ekte unit tests, men...
    • Det tar lang tid
    • Det er lite fleksibelt
       
  • Hver test er uavhengig
    • Rekkefølge har ikke noe å si
    • Vet ikke om de andre testene

Unit testing i Node

  • Bruker bare Mocha og Chai (ikke Protractor)
    • Kjører testene direkte med Mocha
  • Nøyaktig samme format som e2e-testene
var expect = require('chai').expect;

var controller = require('../../../server-node/controllers/items');

describe('controllers.items', function() {
	it('should exist', function() {
		expect(controller).to.exist;
	});
});
$ mocha test/node/controllers/items.spec.js

test/mocha.opts: finds all tests in test/node recursively

test/node
−−recursive

Reporters

  • Standard reporter er ofte nok
    • Forteller hvilke biter av koden som er testet
       
  • Mer konsise reporters finnes: $ mocha -R nyan

Test coverage

$npm install --save-dev blanket

Neste gang

$ npm test

Endelig noe annet enn dependencies i package.json!

{
    "name": "itemsApp",
    "dependencies: "<@\dots@>",
    "devDependencies": "<@\dots@>",
    "scripts": {
        "test: "./node_modules/.bin/mocha && ./node_modules/.bin/protractor"
    }
}

package.json

$ npm test

PS: Man kan definere andre scripts også!

Øving

  • Sett opp (eller bruk) en side med registrering og innlogging
     
    • Les kapittel 10 i boka
      • Skriv e2e-tester for både registrering og innlogging
         
    • Les kapittel 11 i boka
    • Organiser controllers i en "Base Router" (pp. 168)
      • Skriv Node "unit" tests for Sessions-controlleren

PG6300-14-09: Testing

By theneva

PG6300-14-09: Testing

  • 668