Front End Testing ve Continuous Integration
TL;DR
Bu yazimda Front End gelistirme surecleri icin test ve CI entegrasyonlarini en iyi yontemlerle (best practice) yapmayi gostermek istiyorum.
Kullanilan teknoloji, library ve servisler ise Grunt, Jasmine, Karma Test Runner, IstanbulJS, Coveralls.io ve Travis CI olacak.
Yaziya ait,
- GitHub reposu buradadir.
- Travis build sayfasi buradadir.
- Coveralls kod coverage gecmisi buradadir.
- Repo’yu clone’ladiktan sonra calistirmak icin suraya bakabilirsiniz.
Suradaki kendi repom icin kabaca Grunt, JasmineJS, Karma, IstanbulJS, Coveralls ve Travis stack’inden olusan bir CI (Continuos Integration) workflow’u oturtmustum. Grunt ile task’lari otomatize ediyorum, Jasmine ile testlerimi yaziyorum, Karma ile testlerimi calistiriyorum, Istanbul ile test coverage bilgilerimi cikartiyorum, Coveralls ile coverage yuzdemi ve coverage gecmisini ogreniyorum ve Travis ile repoma her push ettigim zaman bu islemlerin otomatik olarak tekrar edilmesini ve testlerimin calistirilmasini ve coverage raporunun Coveralls’a gonderilmesini sagliyorum.
Yukardaki workflow’u oturtmak hic kolay olmadi. Cunku bu kadar araci ve servisi entegre edip bir arada calisacagi bir sistem ortaya cikarmak oldukca zahmetli ve ogrenilecek cok materyal iceriyor. Ayrica daha burada belirtmedigim -yazinin konusu ile ilgili olmayan- bir suru baska Grunt task’im daha var. Onlarinda karmasikligi isin icine girince isler bir adim daha zorlasiyor.
Bu yaziyi hem kendime referans olmasi hem de bu kadar bilgiyi paylasmak icin yaziyorum ve oldukca uzun bir yazi olacaga benziyor. Yapacagimiz islerin listesi su sekilde olacak.
- Yeni bir GitHub repo’su olusturacagiz.
- Modul yonetimi icin
package.json
‘imizi olusturacagiz. - Task’larimizi yonetmek icin
Gruntfile.coffee
‘imizi olusturacagiz. - Uygulamamiza ait kodlari yazacagiz.
- JasmineJS ile uygulamamizin testlerini yazacagiz.
- Testlerimizi calistirmak icin Karma Test Runner’i entegre edecegiz.
- IstanbulJS kullanarak kod coverage raporumuzu elde edecegiz.
- Coveralls.io ile coverage durum ve gecmisimiz
- Travis ile CI entegrasyonu saglamis olacagiz.
Bu adimlardan sonra gelistirme ortamimizda dosyalarimizi her kaydettigimiz zaman testlerimizin tekrar calismasini ve repomuza her push ettigimiz zaman testlerimizin baska bir ortamda calismasini saglamis olacagiz.
GitHub uzerinde yeni bir repo olusturduktan sonra ilk adim olarak package.json ile baslayalim.
package.json
Grunt kullanacagimiz icin npm kullanmamiz gerekiyor. Ilk adimimiz npm icin gerekli olan package.json
olusturmak. Bunun icin en kolay yol calisma dizinimizde npm init
demek. npm-init
package.json
‘i olusturmak icin repo’muz hakkinda bir kac soru soracak ve asagidaki package.json
‘i olusturacak. npm-init
log’unu da suradaki Gist’de gorebilirsiniz.
1 | { |
Gruntfile.coffee
Bu yazidaki ornek kodlar icin CoffeeScript kullanacagim. CoffeScript, JavaScript’e alternatif yazim sekli olan bir dil. Daha kisa, hizli ve anlasilir bir sekilde kod yazmamiza olanak sagliyor. CoffeeScript kullanacagimiz icin Gruntfile’imiz da coffee formatinda olacak. Asagidaki gibi basit ve bos bir Gruntfile.coffee
olusturalim.
1 | module.exports = (grunt) -> |
Gruntfile’imiz hazir olduguna gore test etmek icin calisma dizinimizde grunt
komutunu calistirmamiz gerekli. Fakat bunu suan yaptigimiz zaman asagidaki gibi bir cikti gorecegiz. Cunku load ettigimiz npm task’ini npm ile yuklemedik.
1 | acetz:fe-ci facet$ grunt |
Gruntfile icinde load ettigimiz task’lari npm install TASK_NAME --save-dev
ile yukleyip package.json
‘imiza otomatik olarak yazilmasini saglayabiliriz. Suan icin bize gerekli olan grunt-npm
‘i yuklemek ve package.json’a kaydetmek icin npm install grunt-npm --save-dev
dememiz lazim. Asagidaki gibi bir cikti gormemiz gerekiyor.
1 | acetz:fe-ci facet$ npm install grunt-npm --save-dev |
Projemiz CoffeeScript ile yazilacagi icin grunt-contrib-coffee
task’ini yuklememiz gerekiyor. Bunun icin npm install grunt-contrib-coffee --save-dev
calistirmamiz gerekiyor.
Buraya kadar geldigimizde package.json
‘imiza --save-dev
kullandigimiz icin su satirlarin npm
tarafindan eklendigini goruyor olmamiz lazim.
1 | "devDependencies": { |
Coffee task’imiz CoffeScript file’larimizi JavaScript’e donusturecek. Fakat bunu yapmasi icin her defasinda bu task’i elle calistirmamiz gerekiyor. Bunu otomatiklestirmek icin bir file watcher task’i kullanmamiz gerekiyor. Bu watcher her file degistigi anda bizim task’larimizi tekrar calistiracak. Task’in adi grunt-contrib-watch
. Yuklemek icin npm install grunt-contrib-watch --save-dev
dememiz gerekiyor.
Bu adimdan sonra Gruntfile’imizi configure etmemiz gerekiyor. Projemiz icin gerekli olan kodlarimizi src
klasoru altina test’lerimizi de tests
klasoru altina ekleyecegiz. build
klasorunu ise bizim disimizda otomatik olarak olusturulan dosyalar icin kullanacagiz. coffee
ve watch
task’larini bu klasor yapisini kullanarak assagidaki Gist’deki gibi configure ettim.
Uygulama kodu
Buraya kadar repo’muz ile ilgili on hazirliklar tamamladik simdi asil kod yazma islemine basliyoruz.
Bu ornek icin basit bir Box class’i yazdim. getWidth
getHeight
clone
scale
gibi 4 tane method’u var. Bu Box class’i verdigimiz top
, right
, bottom
ve left
degerlerine gore o koordinatlarda bir Box olusturacak. Bu yazi icin basit bir class yazip icine 3-5 tane basit method ekleyebilecegim bir ornek dusunuyordum. Aklima Closure Library’nin Box class’i geldi. Onun kucuk ve basit bir ornegini yaptim diyebilirim. Closure Library’de bu Box class’i element’lerin width, height, margin, padding gibi degerlerini hesaplamak icin kullaniliyor. Bizim ornegimizdeki basit Box class’ini asagidak Gist’de gorebilirsiniz.
Asagidaki kodun koordinat duzlemi uzerindeki halini su sekilde olacaktir.
1 | new Box |
Testlerimiz
Ideal durumda once test’ler sonra kod yazilir. Buna Red to Green Testing diyorlar. Yani once kirmiziyi gor sonra yesile cevir. Kirmizidan kasit fail eden test, yesilden kasit ise pass eden test. Fakat ben bu yazimda tam tersini yapicam. Siz yaptigimi degil dedigimi yapin :)
Test framework’u olarak ben Jasmine tercih ediyorum. Oldukca basit bir API’a sahip, async test yazmak sadece bir function cagirmak kadar kolay. Uzun zamandan beri kullaniyorum, gayet yeterli ve basit oldugunu dusunuyorum.
Box class’imiz icin yazdigim testleri asagidaki Gist’de gorebilirsiniz.
Karma Test Runner
Karma AngularJS takimi tarafindan gelistirilmis bir test runner ve oldukca basarili. Calistirmasi ve yonetmesi gayet kolay. Kendi icinde watcher’i ile geliyor. Farkli browser’larda calistirmak icin sadece browser ismini yazmamiz yeterli oluyor. Biz bu ornekte Grunt icinde kullanacagiz ve Karma watcher’ini kullanmayacagiz.
Oncelikle bir karma.conf.js
‘a ihtiyacimiz var. Ornek bir karma.conf.js
i asagidaki Gist’de gorebilirsiniz.
Simdi Karma test runner’i Grunt ile entegre etmemiz lazim. Bunun icin once grunt-karma
paketini yuklememiz gerekiyor. Karma ile testlerimizi PhantomJS ve Chrome browser’inda calistirmayi dusunuyorum. Dolayisiyla Karma PhantomJS ve Chrome launcher’larini da yuklememiz gerekiyor. Ayrica testlerimizi Jasmine ile yazdigimiz icin Karma Jasmine’i de yuklememiz gerekiyor.
1 | npm install grunt-karma --save-dev |
karma :
tests :
configFile : ‘karma.conf.js’
1 |
|
grunt.loadNpmTasks ‘grunt-karma’
1 |
|
grunt.registerTask ‘default’, ‘Default task’, ->
grunt.task.run [
‘coffee’
‘karma’
‘watch’
]
1 |
|
acetz:fe-ci facet$ grunt
Running “default” task
Running “coffee:src” (coffee) task
1 files created.
Running “coffee:tests” (coffee) task
1 files created.
Running “karma:tests” (karma) task
INFO [karma]: Karma v0.12.28 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Mac OS X)]: Connected on socket 3lBTlIgNmRlo9kBaPnzW with id 9367162
……
PhantomJS 1.9.8 (Mac OS X): Executed 6 of 6 SUCCESS (0.002 secs / 0.002 secs)
……
Chrome 39.0.2171 (Mac OS X 10.10.0): Executed 6 of 6 SUCCESS (0.027 secs / 0.01 secs)
TOTAL: 12 SUCCESS
Running “watch” task
Waiting…
1 |
|
npm install karma-coverage –save-dev
1 |
|
preprocessors: {
‘build/tests/*/.js’: [‘coverage’]
},
reporters: [‘dots’, ‘coverage’],
coverageReporter: {
type: ‘lcov’,
dir: ‘build/coverage/‘
}
1 |
|
language: node_js
node_js:
- ‘0.10’
install: - npm -d install
- npm install -g grunt-cli
- npm install -g grunt
script: - grunt cinpm install coveralls –save-dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Simdi bir repomuza yeni bir push yaptigimiz zaman Travis'in test'lerimizi calistiriyor olmasi gerekiyor. Soyle bir ekran gormeniz lazim.
![http://take.ms/flV4y](http://take.ms/flV4y)
Hatta soyle guzel bir mail almaniz da lazim.
![http://take.ms/yctn2](http://take.ms/yctn2)
Travis benim tercih ettigim CI araci. Travis'e alternatif olarak drone.io, wercker.com gibi araclari da kullanabilirsiniz. Sanirim Travis aralarinda en stabil olani ve digerleri gibi public repo'lar icin ucretsiz.
### Coveralls
Travis ile CI olayimizi da hallettigimize gore son adim, Istanbul adiminda olusturdugumuz kod coverage dosyasini Coveralls'a gondermeyi saglamak ve Coveralls.io'da kod coverage gecmisimizi gormek.
Bunun icin once Coveralls.io'ya GitHub ile login olmaniz lazim. Daha sonra tipki Travis'de yaptigimiz gibi repo'larinizin oldugu sayfada kendi repo'nuzu Coveralls'da aktif hale getirmeniz lazim. Asagidaki gorselde gorebilirsiniz.
![http://take.ms/3fJEk](http://take.ms/3fJEk)
Daha sonrasinda `coveralls` npm paketini yuklemek gerekiyor.after_script:1
2
3
Ve son olarak `.travis.yml`'a build bittikten sonra coverage data'mizi Coveralls'a gondermesini soylememiz lazim. - cat ./build/coverage/**/lcov.info | ./node_modules/coveralls/bin/coveralls.js
Bu asamadan sonra coveralls.io’da soyle bir ekran goruyor olmaniz lazim.
Build Status ve Coverage badge’lerinin repo’ya eklenmesi
Coveralls’un sayfasindaki BADGE URLS
linkinden Markdown’u kopyalayalim. Asagidaki gorselde gorebilirsiniz.
Ve Travis’in sayfasinda da Build Passing
badge’ine tiklayinca cikan modal’daki Markdown’u kopyalayalim. Asagidaki gorselde gorebilirsiniz.
Bu islem sonunda ve seklinde iki tane badge elde ettik. Bu markdown’lari repo’muz icindeki README.md’ye paste edip repo’muzdaki README.md’mizi senlendirebiliriz.
Bu blog post’un hakki aslinda 3-4 farkli blog post olmak. Ilerleyen zamanlarda TDD ve BDD hakkinda daha cok yazi yazmak istiyorum. O yazilarda Jasmine ve Karma’ya daha genis deginirim. Fakat bu yazinin da genel olarak guzel bir amaca hizmet ettigini dusunuyorum. Bastan asaga bir entegrasyon yapmis olduk. Yazi altina yorumlarinizi ve GitHub repo‘suna star, fork ve PR’lerinizi bekliyorum. Hatta hatirlatayim PR gonderirseniz Travis’de bir build baslar, su adrese gidip gorebilirsiniz.
ccc. şuku matters. ccc.
Baska yazilarda gorusmek uzere, saglicakla…
Comments