Grunt, Protractor, ja Istanbul kattavuusraportit e2e-testeille

Tuli ajankohtaiseksi pohtia voiko API ja E2E testeistä saada koodikattavuusanalyysejä. Käy ilmi, että Angular-alustalla Protractor ajoista voi. Yritin ensin helppoa reittiä valmiin grunt-protractor-coverage plug-inin kanssa, mutta törmäsin toistuvasti kahteen ärsyttävään virheeseen joista ei löytynyt lisätietoa ja jotka eivät ratkeeneet. Joten löysin ratkaisun joka on vielä yksinkertaisemmista paloista koottu: Instanbul moduuli ja vähän magiaa.

Istanbulille on tehty monia Grunt-plugineita, itse päädyin käyttämään perusmallia taichi.

https://github.com/taichi/grunt-istanbul

Plugarin asennus ja lataus on ihan normikamaa. Tärkeät taskimäärittelyt ovat instrument, ja makeReport.

Instrument tähän tapaan:

    instrument: {
      files: 'app/*.js',
      options: {
        lazy: true,
        basePath: 'test/coverage/instrument/'
      }
    }

Tuossa app/*.js on kansio jossa koodit muhivat, ja test/coverage/instrument on kansio johon instrumentoidut versiot koodista kopioituvat. Tämä prosessi muuttaa koodien rakennetta rajusti joten todella syytä pitää erillisiä kopioita, ja suojata omat lähdekoodit.

Tämän magian kannalta on hyvä lisätä vielä coverageVariable muuttuja, eli lopullinen ratkaisu tässä:

    instrument: {
      files: 'app/*.js',
      options: {
        lazy: true,
        coverageVariable: '__coverage__',
        basePath: 'test/coverage/instrument/'
      }
    }

Näin kun tätä instrumentoitua koodia ajetaan, kutsut päivitetään tähän globaaliin coverage muuttujaan – jonka me voimme napata (oletusnimi on aika härpäke aikaleimoineen, siksi määrittelemme sen uudelleen).

Tämän ohella on syytä clean-taskilla putsata ensin coverage kansio, sitten copy-taskilla siirtää kaikki ei-javascript tauhkat joita e2e testaukseen tarvitaan, sisältäen esim. html, kuvatiedostot, tyylisivut, jne – tietysti valmiiksi prosessoituna e2e-käyttöön kelvollisina. Tässä esimerkki copy-taskin sisällöstä:

coverageE2E: {
 files: [
 {expand: true, cwd: './dist/lib', src: '**/*.*', dest: 'coverageE2E/lib'},
 {expand: true, cwd: './dist/', src: '**/*.html', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.png', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.jpg', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.gif', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.ico', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.svg', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.css', dest: 'coverageE2E'},
 {expand: true, cwd: './dist', src: '**/*.css', dest: 'coverageE2E'},
 {expand: true, cwd: './dist/fonts', src: '*.*', dest: 'coverageE2E/fonts'},
 {expand: true, cwd: './dist/lib', src: '*.*', dest: 'coverageE2E/lib'},
 {expand: true, cwd: './WEB-INF', src: '*.*', dest: 'coverageE2E/WEB-INF'},
 // Here, extra copy operation since istanbul puts instrumented code in a subdir to a wrong path
 {expand: true, cwd: './coverageE2E/dist', src: '**/*.*', dest: './coverageE2E'}
 ]
 }

Nyt kun asiaa oikein ääneen mietin, niin kenties tätäkin voisi yleistää, esim. kopioi kaikki ei- .js päätteiset tiedostot?

Nykyisellään Istanbul instrumentointi pakottaa kohdekansioon hakemistorakenteen missä lähdekansio on – joka ei ole aina haluttua. En löytänyt pluginista säätöjä, joten tuossa copy taskissa kopioidaan dist-kansion sisältö tasoa ylemmäs, jotta se on rakenteessa jota itse käytän myös testeihin ja tuotantoon.

Seuraavaksi tulee se dirty trick: Napataan kerätty __coverage__ muuttuja ja kirjoitellaan se tiedostoon, jahka kaikki coverage on kerätty. Tämä on aivan varmasti tehtävissä nätimminkin – mutta tässä on esimerkkinä protractor-taskin onComplete-funktio joka ajetaan sen lopuksi:

onComplete: function() {
  // Let's write code coverage analysis to a file!
  browser.driver.executeScript("return __coverage__;").then(function(val) {
  fs.writeFileSync("coverageE2E/coverage.json", JSON.stringify(val));
  });
}

Lopuksi analysoidaan coverage.json tiedosto makeReport-taskilla:

module.exports = {
 src: 'coverageE2E/coverage.json',
 options: {
 type: 'lcov',
 dir: '../../../target/e2ecoverage',
 print: 'detail'
 }
};

Ja tässä kooste koko e2e_coverage taskista:

 

 

module.exports = function(grunt) {
 grunt.registerTask('e2e_coverage', [
   'dev', // First do normal build to /dist folder
   'clean:coverageE2E', // clean away old instrumented code
   'instrument', // Instrument all javascript files to instrumented folder using Istanbul
   'copy:coverageE2E', // Copy all non-javascript resources from dist to instrumented code
   'express:coverageE2E', // Run express server using instrumented folder, not dist folder
   'protractor:coverage', // Run protractor tests using instrumented folder
   'makeReport' // Use Istanbul reporting
  ]);
};

Eli tiiviisti: Käännä, putsaa vanhat pois, instrumentoi koodi Istanbulilla, kopioi html:t, tyylisivut ja kuvat sinne sekaan, aja serveri ja protractor testit instrumentoidun koodin kansiosta, ja rakenna raportti tuotoksista, taas Istanbul-pluginilla.

Nyt – tätä olisi mukavaa analysoida Sonarissa, mutta näyttäisi että siellä on Javascript-pluginissa paikka vain yhdelle lcov tiedostolle…

Huom. myös – tuon coverage tiedon keruuvaiheen voisi tehdä elegantimminkin grunt-protractor-coverage pluginilla, löytyy täältä:

https://www.npmjs.org/package/grunt-protractor-coverage

Omissa kokeiluissa en kuitenkaan saanut tuota toimimaan, se antoi kahta eri virhettä – voi johtua käytössä olevista kirjastokombinaatioista, kansiorakenteista, tms, mutta en viitsinyt haaskata siihen enempää aikaa.

Mainokset

Vastaa

Täytä tietosi alle tai klikkaa kuvaketta kirjautuaksesi sisään:

WordPress.com-logo

Olet kommentoimassa WordPress.com -tilin nimissä. Log Out / Muuta )

Twitter-kuva

Olet kommentoimassa Twitter -tilin nimissä. Log Out / Muuta )

Facebook-kuva

Olet kommentoimassa Facebook -tilin nimissä. Log Out / Muuta )

Google+ photo

Olet kommentoimassa Google+ -tilin nimissä. Log Out / Muuta )

Muodostetaan yhteyttä palveluun %s