EPHPC Webinar Slides: Unit Testing by Arthur Purnama
1. Unit Testing
Merangkak Menuju Pengembangan Aplikasi
PHP yang Berkualitas dan Tahan Banting
Arthur Purnama
arthur [at] purnama.de
http://arthur.purnama.de
06.04.2011
2. Arthur Purnama
Diplom Informatiker Hochschule Fulda
Sejak 2004 bekerja sebagai PHP
Programmer
Sejak 2008 bekerja sebagai ITConsultant
divisi Portal Solutions
Saat ini tinggal di Frankfurt am Main, Jerman
3. Tujuan
Memperkenalkan Unit Testing
Mendorong atau memotivasi penggunaan
Unit Testing
Memperkenalkan Unit Testing Framework
PHPUnit
4. Rutinitas Test Programer PHP
Berjam-jam mencari bug
Debugger? apaan tuh?
Teman setia: echo, print_r, var_dump
Mati satu tumbuh seribu (bug baru)
Bug Lama Bersemi Kembali
5. Unit Testing
In computer programming, unit testing is a
method by which individual units of source
code are tested to determine if they are fit for
use.
A unit is the smallest testable part of an
application.
In object-oriented programming a unit is
usually a method.
http://en.wikipedia.org/wiki/Unit_testing
6. Unit Testing
Dalam pemrograman komputer, unit testing
merupakan suatu metode yang mana satu
unit dalam source code diuji untuk
menunjukkan bahwa code tersebut bekerja
sebagaimana mestinya.
Unit adalah bagian terkecil dari satu aplikasi
yang dapat diuji.
Dalam pemrograman berorientasi obyek, unit
biasanya adalah method.
8. Kelebihan Unit Testing
Yakin setiap saat bahwa code berfungsi
sebagaimana mestinya.
Yakin setiap kali aplikasi berkembang, code
tetap berfungsi sebagaimana mestinya.
Yakin setiap kali melakukan re-design atau
refakturisasi, code tetap berfungsi
sebagaimana mestinya.
9. Kelebihan Unit Testing
Menjadi bagian dari dokumentasi code
Mempermudah Integrasi antar komponen
Meningkatkan kualitas code
10. Unsur Unit Testing
Harus di otomatisasi
Dapat dijalankan dengan sekali klick
Dapat dengan mudah diulang
Mudah diimplementasikan
Setelah ditulis dapat dijalankan kapan saja
Setiap orang dapat menjalankannya
Berjalan dengan cepat
11. Unit Test != Integration Test
Unit Test
Tidak berinteraksi dengan basis data
Tidak berinteraksi dengan Jaringan
Tidak berinteraksi dengan File System
Tidak membutuhkan konfigurasi khusus untuk
menjalankannya
Terisolasi dari komponen atau kelas konkrit
lainnya
12. Unit Testing Framework
PHPUnit
Unit Testing Framework
Ditulis oleh Sebastian Bergmann
De facto standard untuk PHP
Banyak didukung oleh Tools dan Framework lain
13. Contoh Unit Testing Multiplikasi
<?php
//MultiplikasiTest.php
require_once 'multiplikasi.php';
class BelajarUnitTest extends PHPUnit_Framework_TestCase{
}
?>
14. Contoh Unit Testing Multiplikasi
<?php
//MultiplikasiTest.php
require_once 'multiplikasi.php';
class BelajarUnitTest extends PHPUnit_Framework_TestCase{
//Nama fungsi menggunakan awalan “test“
public function testMultiplicate(){
}
}
?>
15. Contoh Unit Testing Multiplikasi
<?php
//MultiplikasiTest.php
require_once 'multiplikasi.php';
class BelajarUnitTest extends PHPUnit_Framework_TestCase{
//Nama fungsi menggunakan awalan “test“
public function testMultiplicate(){
$this->assertEquals(2, multiplicate(1, 2));
}
}
?>
16. Contoh Unit Testing Multiplikasi
$>phpunit BelajarUnitTest MultiplikasiTest.php
PHPUnit 3.5.12 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 3.00Mb
OK (1 test, 1 assertion)
17. Contoh Unit Testing Multiplikasi
<?php
//MultiplikasiTest.php
require_once 'multiplikasi.php';
class BelajarUnitTest extends PHPUnit_Framework_TestCase{
public function testMultiplicate(){
//Sangat tidak dianjurkan. Pastikan hanya selalu menguji SATU hal
$this->assertEquals(2, multiplicate(1, 2));
$this->assertEquals(5, multiplicate(3, 2));
$this->assertEquals(4, multiplicate(2, 2));
}
}
?>
18. Contoh Unit Testing Multiplikasi
$>phpunit BelajarUnitTest MultiplikasiTest.php
PHPUnit 3.5.12 by Sebastian Bergmann.
F
Time: 0 seconds, Memory: 3.00Mb
There was 1 failure:
1) BelajarUnitTest::testMultiplicate
Failed asserting that <integer:6> matches expected <integer:5>.
$MultiplikasiTest.php:10
FAILURES!
Tests: 1, Assertions: 2, Failures: 1.
19. Contoh Unit Testing Multiplikasi
<?php
//MultiplikasiTest.php
require_once 'multiplikasi.php';
class BelajarUnitTest extends PHPUnit_Framework_TestCase{
public function testMultiplicate1And2(){
$this->assertEquals(2, multiplicate(1, 2));
}
public function testMultiplicate3And2(){
$this->assertEquals(5, multiplicate(3, 2));
}
public function testMultiplicate2And2(){
$this->assertEquals(4, multiplicate(2, 2));
}
}
?>
20. Contoh Unit Testing Multiplikasi
$>phpunit MultiplikasiTest.php
PHPUnit 3.5.12 by Sebastian Bergmann.
.F.
Time: 0 seconds, Memory: 3.00Mb
There was 1 failure:
1) BelajarUnitTest::testMultiplicate3And2
Failed asserting that <integer:6> matches expected <integer:5>.
$MultiplikasiTest.php:12
FAILURES!
Tests: 3, Assertions: 3, Failures: 1.
21. Contoh Unit Testing Multiplikasi
<?php
//MultiplikasiTest.php
require_once 'multiplikasi.php';
class BelajarUnitTest extends PHPUnit_Framework_TestCase{
public function testMultiplicate1And2(){
$this->assertEquals(2, multiplicate(1, 2));
}
public function testMultiplicate3And2(){
$this->assertNotEquals(5, multiplicate(3, 2));
}
public function testMultiplicate2And2(){
$this->assertEquals(4, multiplicate(2, 2));
}
}
?>
22. Contoh Unit Testing Multiplikasi
$>phpunit BelajarUnitTest MultiplikasiTest.php
PHPUnit 3.5.12 by Sebastian Bergmann.
...
Time: 0 seconds, Memory: 3.00Mb
OK (3 tests, 3 assertions)
23. Contoh Unit Testing Multiplikasi
$>phpunit --testdox BelajarUnitTest MultiplikasiTest.php
PHPUnit 3.5.12 by Sebastian Bergmann.
BelajarUnitTest
[x] Multiplicate 1 and 2
[x] Multiplicate 3 and 2
[x] Multiplicate 2 and 2
24. Tapi.. Code saya seperti ini..
<?php
// Connects to your Database
mysql_connect ( "your.hostaddress.com", "username", "password" ) or die ( mysql_error () );
mysql_select_db ( "Database_Name" ) or die ( mysql_error () );
//checks cookies to make sure they are logged in
if (isset ( $_SESSION ['ID_my_site'] )) {
$username = $_ SESSION ['ID_my_site'];
$pass = $_ SESSION ['Key_my_site'];
$check = mysql_query ( "SELECT * FROM users WHERE username = '$username'" ) or die ( mysql_error () );
$result = mysql_fetch_array ( $check );
foreach ( $result as $info ) {
//if the cookie has the wrong password, they are taken to the login page
if ($pass != $info ['password']) {
header ( "Location: login.php" );
} else { //otherwise they are shown the admin area
echo "<p>Admin Area</p>";
echo "<p>Your Content<p>";
echo "<a href=logout.php>Logout</a>";
}
}
} else {
//if the cookie does not exist, they are taken to the login screen
header ( "Location: login.php" );
}
?>
25. Core techniques
Refactoring
Separation of Concern
Inversion of Control (Dependency Injection)
Design by Contract
Design Patterns
26. Contoh Refactoring
<?php
namespace myappsecurity;
use myappdaosinterfacesUser;
use myapputilinterfacesSession;
class Authorize implements interfacesAuthorize{
private $userDAO;
private $session;
public function __construct(User $userDAO, Session $session) {
$this->userDAO = $userDAO;
$this->session = $session;
}
public function isAuthorize(){
if($this->session->isAuthenticate()){
$user = $this->userDAO->getByUsername($this->session->getUsername());
return $this->session->getPassword() === $user->getPassword();
}else{
return false;
}
}
}
?>
27. Mocks & Stubs
<?php <?php
namespace myappmocks; namespace myappmocks;
use myappdaosinterfacesUser; use myapputilinterfacesSession;
class UserPalsu implements User{ class SessionPalsu implements Session{
public function getById($id){ public function getUsername(){
return null; return null;
} }
public function getByUsername($username){ public function getPassword(){
return null; return null;
} }
public function getAll(){ public function isAuthenticate(){
return null; return false;
} }
} }
?> ?>
28. Unit Test Authorize
<?php
use myappsecurityAuthorize;
use myappmocksSessionPalsu;
use myappmocksUserPalsu;
class AuthorizeTest extends PHPUnit_Framework_TestCase {
public function testIsAuthorizeSessionNotAuthenticate(){
$userDAO = new UserPalsu();
$session = new SessionPalsu();
$authorize = new Authorize($userDAO, $session);
$this->assertFalse($authorize->isAuthorize());
}
}
?>
29. Mocks & Stubs
<?php <?php
namespace myappmocks; namespace myappmocks;
use myappmodels; use myapputilinterfacesSession;
class SessionPalsu implements Session{
use myappdaosinterfacesUser;
private $username;
class UserPalsu implements User{
private $password;
private $user; private $authenticate;
public function getById($id){ public function getUsername() {
return null; return $this->username;
} }
public function setUsername($username) {
public function getByUsername($username){ $this->username = $username;
return $this->user; }
public function getPassword() {
}
return $this->password;
}
public function getAll(){ public function setPassword($password) {
return null; $this->password = $password;
} }
public function isAuthenticate(){
public function return $this->authenticate;
setUser(modelsinterfacesUser $user){ }
$this->user = $user; public function setAuthenticate($authenticate){
} $this->authenticate = $authenticate;
} }
}
?>
?>
30. Unit Test Authorize
<?php
use myappmodelsUser;
use myappsecurityAuthorize;
use myappmocksSessionPalsu;
use myappmocksUserPalsu;
class AuthorizeTest extends PHPUnit_Framework_TestCase {
//public function testIsAuthorizeSessionNotAuthenticate(){...
public function testIsAuthorizeSessionAuthenticateButWrongPassword(){
$userDAO = new UserPalsu();
$user = new User("username", "password");
$userDAO->setUser($user);
$session = new SessionPalsu();
$session->setPassword("wrongpassword");
$authorize = new Authorize($userDAO, $session);
$this->assertFalse($authorize->isAuthorize());
}
public function testIsAuthorizeSessionAuthenticateCorrectPassword(){
$userDAO = new UserPalsu();
$user = new User("username", "password");
$userDAO->setUser($user);
$session = new SessionPalsu();
$session->setPassword("password");
$authorize = new Authorize($userDAO, $session);
$this->assertTrue($authorize->isAuthorize());
}
}
?>
32. Fixtures
<?php
use myappmodelsUser;
use myappsecurityAuthorize;
use myappmocksSessionPalsu;
use myappmocksUserPalsu;
class AuthorizeTest extends PHPUnit_Framework_TestCase {
private $userDAO;
private $session;
public function setUp(){
$this->userDAO = new UserPalsu();
$user = new User("username", "password");
$this->userDAO->setUser($user);
$this->session = new SessionPalsu();
$this->session->setAuthenticate(true);
}
public function tearDown(){
$this->userDAO = null;
$this->session = null;
}
//public function testIsAuthorizeSessionNotAuthenticate(){..
public function testIsAuthorizeSessionAuthenticateButWrongPassword(){
$this->session->setPassword("wrongpassword");
$authorize = new Authorize($this->userDAO, $this->session);
$this->assertFalse($authorize->isAuthorize());
}
public function testIsAuthorizeSessionAuthenticateCorrectPassword(){
$this->session->setPassword("password");
$authorize = new Authorize($this->userDAO, $this->session);
$this->assertTrue($authorize->isAuthorize());
}
}?>
38. Memulai Unit Testing
Yakinkan diri sendiri
Kumpulkan Case Study atau Success Story
http://biblio.gdinwiddie.com/biblio/StudiesOfTestDrivenDevelopment
Cari Pendukung / Panggil Konsultan
Tentukan Tujuan
Catat Perkembangan
Bersiap menghadapi rintangan
39. Kemana Setelah Ini
Metodologi
Test Driven Development
Behaviour Driven Development
Tools Pendukung
IDE (Zend Studio, PHPStorm, PDT, NetBeans)
Build Automation (Ant, Maven, Phing)
Continuous Integration
Test Lain menggunakan PHPUnit
Database Testing
UI Testing (Selenium)
Diskusi terbuka di Milist / Groups
40. Referensi
Wikipedia
http://en.wikipedia.org/wiki/Unit_testing
„PHPUnit Manual“ – Sebastian Bergmann
http://www.phpunit.de/manual/current/en/
„Getting Started With PHPUnit “ – Sebastian
Bergmann
http://www.slideshare.net/sebastian_bergmann/getting-started-with-phpunit
„The Art of Unit Testing“ - Roy Osherove
„Unit Testing Fundamentals“ – Richard Paul
http://www.slideshare.net/rapaul/unit-testing-fundamentals
„Embrace Unit Testing“ – Alessio Pace
http://www.slideshare.net/alessiopace/embrace-unit-testing