Noch knapp zwei Wochen…

Die schriftliche Ausarbeitung meiner Diplomarbeit bei der MY-HAMMER AG mit dem Thema „Umstrukturierung einer Webapplikation von der prozeduralen zur objektorientierten Programmierung“ habe in dreifacher Ausführung in der Fontys eingereicht und am Freitag, dem 29.07.2007, halte ich meine Abschlusspräsentation. Dann habe ich es endlich geschafft! Dann bin ich… Hm, was bin ich dann eigentlich? Oo Das weiß ich ehrlich gesagt garnicht so genau. Es gibt da einige Titel, die in Frage kommen:

  • Bachelor of Information Technology,
  • Dipl.-Inf. (FH),
  • Dipl.-Ing. (NL),
  • Ing. (Bachelor of ICT),
  • oder etwas völlig anderes.

Ich bin mal gespannt!

Aber wie geht es dann nach dem Studium weiter??? Rucksacktour quer durch die Welt oder direkt zum Arbeitsamt? Schmarn! Ich habe heute meinen Arbeitsvertrag unterschrieben zurück bekommen. Ab dem 01.07.2007 trete ich meine Stelle als Webapplikationsentwickler bei der MY-HAMMER AG an. Es geht also nahtlos weiter. Jetzt muss ich nur noch den 29.06.2007 abwarten und auf eine gute Note hoffen.

PHPUnit und die auf Eclipse basierende PHP-IDE PDT

Im folgenden Text wird beschrieben, wie man das UnitTest Framework PHPUnit 3.0.3 manuell (ohne PEAR)
unter Windows installiert und im auf Eclipse basierenden
PDT (PHP Development Tool) einbindet.

Requirements:

Es empfihelt sich hier, jeweils die aktuellste Version herunter zu laden. Bei XDebug muss man eventuell ein paar
Versionen testen, da jede PHP-Version ihr eigenes XDebug-Modul braucht.

Installation

Nachdem man die jeweils aktuellste Version heruntergeladen hat, entpackt man die Archive in separate temporäre Verzeichnisse.
Das Eclipse-Verzeichnis (von PDT) verschiebt man nun in sein Programmverzeichnis (z.B. „D:\Programme\Eclipse“).
Das PHPUnit-Verzeichnis verschiebt man nun an eine beliebige Stelle. Eine vermeintlich sinnvolle Stelle wäre D:\Programme\Eclipse\frameworks\PHPUnit3.
Dieses Verzeichnis muss nun in die Umgebungsvariable PATH eingetragen werden. Hierzu macht man einen Rechtsklick auf den
Arbeitsplatz und wählt dann „Eigenschaften“ aus. In dem neuen Fenster wählt man dann den Reiter/die Registerkarte „Erweitert“ aus, wo man dann
auf den Button „Umgebungsvariablen“ klickt. Hier sind nun zwei Felder zu sehen:

  • oben: Umgebungsvariablen des angemeldeten Benutzers
  • unten: Umgebungsvariablen des Systems

Man kann die PATH-Variable in beiden Feldern ändern. Wenn man der einzige Benutzer des Systems ist und Administratorrechte hat, dann empfiehlt sich, die PATH-Variable des Systems anzupassen. Anderenfalls die des aktuellen Benutzers (gilt tatsächlich ausschließlich für den aktuell angemeldeten Benutzer!).
Im System-Fenster sollte schon eine entsprechende Variable vorhanden sein. Diese wählt man aus und klickt auf „Bearbeiten“. Sollte sie nicht vorhanden sein (in den meisten Fällen ist dem so im Benutzer-Fenster), dann klickt man auf „Neu“, trägt in der obersten Zeile „PATH“ ein (ohne die Anführungszeichen) und unten den Pfad zum PHPUnit-Verzeichnis (z.B. „D:\Programme\Eclipse\PHPUnit3“).
Der Vollständigkeit halber fügen wir noch den „.“ hinzu, der für das aktuelle Verzeichnis steht. Demnach sollte die PATH-Variable in unserem Fall wie folgt aussehen:

.;D:\Programme\Eclipse\PHPUnit3

Nun klickt man auf „OK“ und die Einstellungen sollten übernommen sein. Als nächstes verschiebt man die XDebug.dll in das PHP-Verzeichnis von PDT.
Dieses befindet sich in unserem Fall hier:

D:\Programme\eclipse\plugins\org.zend.php.debug.debugger.win32.x86_0.1.7\resources\php5

In dem gleichen Verzeichnis befindet sich auch die php.ini, die noch editiert werden muss. Hier müssen einige Pfade angegeben werd.
Zunächst setzen wir ein „;“ vor die Zeile „zend_extension_ts=.\ZendDebugger.dll“. Damit deaktivieren wir die Zend-Extension, da XDebug damit nicht kompatibel ist.
Damit der PHP-Interpreter das Verzeichnis von PHPUnit findet, muss dies in der php.ini mit „ini_path“ festgelegt werden:

ini_path=“D:\Programme\eclipse\frameworks\PHPUnit3″

Damit PHPUnit seine Scripte findet, muss der „include_path“ noch gesetzt werden. Hier werden folgende Verzeichnisse angegeben:

  • Pfad zum PHPUnit-Hauptverzeichnis: D:\Programme\eclipse\frameworks\PHPUnit3
  • Pfad zum Eclipse Workspace: C:\Dokumente und Einstellungen\redbrick\workspace\myWebProjekt
  • Pfad zu den Tests: C:\Dokumente und Einstellungen\redbrick\workspace\myWebProjekt\tests

Diese Pfade werden mit einem „;“ separiert und in die gleiche Zeile geschrieben.
Zum Schluss muss noch das XDebug-Modul geladen werden. Dazu setzt man den Parameter zend_extension_ts und setz den Pfad zur php_xdebug.dll:

"D:\Programme\eclipse\plugins\org.zend.php.debug.debugger.win32.x86_0.1.7\ resources\php5\php_xdebug.dll"

Die Beispiel php.ini zum hier verwendeten Szenario gibt es hier.

Damit PDT (oder man selber aus der Windows-Konsole heraus) direkt PHPUnit aufrufen kann, wird mit dem Framework eine entsprechende Batchdatei mitgeliefert.
Diese befindet sich in dem Hauptverzeichnis von PHPUnit und heißt „pear-phpunit.bat“. Hier müssen ein paar Änderungen vorgenommen werden.

  • „@php_bin@“ muss jeweils durch den exakten Pfad zum PHP-Parser (php.exe) ersetz werden
  • „@php_dir@“ muss durch den exakten Pfad zum Hauptverzeichnis von PHPUnit ersetzt werden

Die Beispiel phpunit.bat zum hier verwendeten Szenario gibt es hier.

Jetzt wird als letztes noch das PHPUnit Framework in PDT (Eclipse) eingebunden. Dazu startet man zunächst Eclipse, erstellt ein neues PHP Projekt (File -> New -> PHP Projekt). In diesem neuen Projekt wird nun das Include-Verzeichnis angepasst:

  • Rechtsklick auf das neue Projekt
  • Configure Include Path
  • In dem Reiter/der Registrierkarte Libraries klickt man auf „Add Variable…“
  • „Configure Variables“
  • „New…“
  • Name: PHPUnit3
  • „Folder…“
  • Zum PHPUnit-Hauptverzeichnis durchklicken (D:\Programme\eclipse\frameworks\PHPUnit3) und bestätigen

Damit wäre die Installation und Konfiguration abgeschlossen und man kann seine UnitTests schreiben.

Beispiel UnitTest: Taschenrechner

Ich gehe hier von einem trivialen Beispiel eines simplen Taschenrechners aus. Hier die Verzeichnisstruktur:

myPhpProjekt\
            |
             - tests\
            |       |
            |        - CalcTest.php
            |
             - Calc.php

Die folgende Klasse mit ihren 6 Methoden/Funktionen befindet sich in der Datei Calc.php, welche sich im Hauptverzeichnis des PHP-Projektes befindet.

class Calc
{
	/**
	 * Speichert das Resultat der Rechenoperationen
	 */
	public $result = NULL;

	/**
	 * Methode/Funktion zum Addieren zweier Zahlen
	 *
	 * @param $var1 Summand 1
	 * @param $var2 Summand 2
	 * @return $result Die Summe der Addition
	 */
	public function add($var1, $var2)
	{
		$result = $var1 + $var2;
		return $result;
	}

	/**
	 * Methode/Funktion zum Subtrahieren zweier Zahlen
	 *
	 * @param $var1 Minuend
	 * @param $var2 Subtrahend
	 * @return $result Die Differenz der subtraktion
	 */
	public function sub($var1, $var2)
	{
		$result = $var1 - $var2;
		return $result;
	}

	/**
	 * Methode/Funktion zum Multiplizieren zweier Zahlen
	 *
	 * @param $var1 Faktor 1
	 * @param $var2 Faktor 2
	 * @return $result Das Produkt der Multiplikation
	 */
	public function mult($var1, $var2)
	{
		$result = $var1 * $var2;
		return $result;
	}

	/**
	 * Methode/Funktion zum Dividieren zweier Zahlen
	 *
	 * @param $var1 Dividend
	 * @param $var2 Divisor
	 * @return $result Der Quotient der Division
	 */
	public function divide($var1, $var2)
	{
		$result = $var1 / $var2;
		return $result;
	}

	/**
	 * Methode/Funktion um das letzte Ergebnis einer Rechenoperation auszulesen
	 *
	 * @return $result if it is set - otherwhise returns false
	 */
	public function getResult()
	{
		if($result != NULL) return $result;
		else return false;
	}

	/**
	 * Methode/Funktion um das letzte Ergebnis zurück zu setzen
	 */
	public function resetResult()
	{
		$this->result = NULL;
	}
}

Die oben angegebene Klasse soll jetzt getestet werden. Dies macht man mit der Datei CalcTest.php, die sich im Verzeichnis „tests“ innerhalb des PHP-Projektes befindet.

/* include the required files */
require_once 'PHPUnit/Framework/TestCase.php';
require_once 'PHPUnit/TextUI/TestRunner.php';
require_once 'Calc.php';

if (!defined('PHPUnit_MAIN_METHOD')) {
    define('PHPUnit_MAIN_METHOD', 'TestCalc::main');
}

class CalcTest extends PHPUnit_Framework_TestCase
{
	/**
	 * Main-Methode zum direkten Starten der Tests
	 */
	public static function main()
	{
		require_once 'PHPUnit/Framework.php';
        	require_once "PHPUnit/TextUI/TestRunner.php";

        	$suite  = new PHPUnit_Framework_TestCase("Calc Test");
        	$result = PHPUnit_TextUI_TestRunner::run($suite);
	}

	private $myCalc;

	/**
	 * Methode zum Erstellen eines Objektes, das getestet werden soll.
	 * Wird vor jedem einzelnen Test aufgerufen -> immer ein frisches Objekt!
	 */
	protected function setUp()
	{
		$this->myCalc = new Calc;
	}

	/**
	 * Funktionstes der Methode add(var1, var2)
	 */
	public function testAdd()
	{
		$this->assertEquals(5, $this->myCalc->add(3,2));
	}

	/**
	 * Funktionstes der Methode sub(var1, var2)
	 */
	public function testSub()
	{
		$this->assertEquals(5, $this->myCalc->sub(10,5));
	}

 	/**
	 * Funktionstes der Methode mult(var1, var2)
	 */
	public function testmult()
	{
		$this->assertEquals(50, $this->myCalc->mult(10,5));
	}

 	/**
	 * Funktionstes der Methode divide(var1, var2)
	 */
	public function testdivide()
	{
        	$this->assertEquals(2, $this->myCalc->divide(10,5));
	}

	/**
	 * Funktionstes der Methode divide(var1, var2):
	 * Eine Exception muss geworfen werden, wenn versucht wird, durch 0 zu dividieren
	 *
	 * Dieser Test ist noch nicht implementiert: markTestIncomplete('Hinweistext')
	 */
	public function testdivide2()
	{
 		$this->markTestIncomplete('Division durch 0 testen.');
	}

	public function testGetResult()
	{
    		$this->assertEquals(NULL, $this->myCalc->getResult());
	}

	/**
	 * Methode zum Löschen eines Objektes nach dem Test.
	 * Wird nach jedem einzelnen Test aufgerufen
	 */
	protected function tearDown()
	{
    		$this->myCalc = NULL;
	}
}

Die beiden PHP-Dateien gibt es hier im Zip-Format zum Download.

Um die Tests auszuführen, gibt es zwei Möglichkeiten. Zum einen aus Eclipse heraus und zum anderen über die Konsole von Windows.

Aus Eclipse heraus:

  • Rechtsklick auf die Test-Klasse CalcTest.php
  • „Run As“
  • „PHP Script“

Aus der Windows-Konsole
Erstellt in dem Verzeichnis C:\Dokumente und Einstellungen\redbrick\Desktop\testReport einen Report des Testlaufs im HTML-Format

phpunit --verbose --report "C:\Dokumente und Einstellungen\redbrick\Desktop\testReport" CalcTest

Ein Hinweis noch zu der Namenskonvention: Die Test-Klassen sollten immer den Namen der zu testenden Klasse tragen, mit der Erweiterung „Test“. In dem hier verwendeten Beispiel wird die Klasse Calc getestet. Also heißt die Testdatei „CalcTest.php“. Ähnliche Regel gilt für die Methoden/Funktionen. Nur steht hier der Zusatz „test“ VOR dem Namen der zu testenden Methoden/Funktion und nicht dahinter.

Weiterführende Links zum Thema

redbrick (14.10.2009 9:10:17)

Nachtrag zum Howto: Unter http://www.phphatesme.com/blog/tools/phpunit-mittels-pti-in-eclipse-einbinden/ gibt es eine weitere sehr gute Anleitung, um PHPUnit in Eclipse/PDT zu integrieren. Diesmal In Deutsch verfasst.

redbrick (15.07.2009 10:23:54)

Nachtrag zum Howto: Unter http://www.phpunit.de/wiki/Eclipse gibt es eine gute Anleitung, wie man PHPUnit in PDT 2.x integrieren kann. Die Anleitung ist in Englisch verfasst und bezieht sich auf eine Linux Desktop-Umgebung. Aber die Anweisungen sollten für MacOS X und auch Windows gleich sein.

Das Studium neigt sich dem Ende zu!

Nachdem ich nun ein Jahr nichts mehr gebloggt habe, gibt es jetzt doch nochmal etwas zu schreiben. Endlich habe ich alle Klausuren und Assessments hinter mir! Und die auch alle äußerst erfolgreich abgeschlossen. Bin sogar knapp an meinem Abschluss mit cum laude vorbeigerauscht – ein wenig ärgerlich…

Jetzt steht mir noch meine Diplomarbeit bevor, die am 5. Februar 2007 beginnt. Und zwar schreibe ich meine Diplomarbeit beim Online-Auktionshaus My-Hammer.de, einem Tocherunternehmen der Abacho AG. Im Januar habe ich mich bereits in das System einarbeiten können. Dabei habe ich auch schon das ein oder andere neue Feature programmiert, das auch schon in Aktion ist. Die Arbeit in dem jungen Team Entwicklung ist sehr angenehm. Ich freue mich schon ungemein auf mein Diplomprojekt, auch wenn ich feststellen musste, dass schon eine lange Wunschliste für mein Projekt existiert (vorwiegend aus dem Service).

In den letzten Tagen habe ich mich mit dem Thema UnitTests für PHP5 auseinandergesetzt. Widererwartens bin ich da auf eine Menge Frameworks gestoßen. Letzten Endes habe ich mich jedoch für PHPUnit entschieden, da es die umfangreichste und am besten strukturierte Umsetzung eines UnitTest Frameworks ist. Es ist eine komplette Prortierung von JUnit zu PHP5, das ich während meines bisherigen Studiums oft genutzt habe. Im Gegensatz zu JUnit geht PHPUnit sogar noch einen Schritt weiter. Neben den üblichen TestCases und TestSuites sind hier auch ohne eine weitere Extension CoverageTests (bei JUnit Hansel) möglich. Hier mal die offizielle Featureliste von phpunit.de:

Zwar ist die Einrichtung von PHPUnit ein wenig umfangreich, sofern man es manuell macht und nicht via PEAR, doch lohnt es sich am Ende auf jeden Fall. Neben der Installation gibt es noch ein weiteres Manko: wenn man einen schönen Report in HTML haben möchte, dann braucht man die PHP-Extension XDebug. Dies hingegen zieht ein weiteres Problem nach sich: es ist derzeit nicht mit Zend kompatibel. Das heißt, man muss die Zend-Extensions alles deaktivieren. Somit empfielt es sich, ein komplett eigenes System aufzusetzen, auf dem man testet.

Ich hoffe, dass ich jetzt wieder öfter mal was schreiben werde. Es sind immerhin schon einige neue HowTo’s geplant Unter anderem ein kleines Howto, wie man PHPUnit manuell (ohne PEAR) unter Windows mit XAMPP installiert und benutzt. Mal sehen, ob ich mich auch wirklich dazu aufreffen kann, die Texte zu schreiben. Da ich das frühe Aufstehen und 8 Stunden Arbeiten absolut nicht mehr gewohnt bin, bin ich nach Feierabend doch häufig zu Müde, um noch etwas produktives zu machen. Nunja, abwarten…

Connecting to a database with Java (oracle)

This howto will show you how to connect to a database (Oracle, MySQL or PostgreSQL) with Java.

In order to connect to a database you will have to download the JDBC driver from the corresponding website and put it into the root directory of your project. If you are using Eclipse you can easiely add this jar file to your project and run the program within Eclipse. If you want to start the program from a comandline, then you have to tell java the classpath where it looks for the driver. For the Oracle thin driver you can do it as follows:

java -classpath .;ojdbc14.jar DbConnect [option]

In the followin program I use 2 switches as option:
clear: clears the table „testTable“
populate: fills the table „testTable“ with content

On some platforms the seperator for the classpathes differs. To get the correct seperator just run

java -help

and look for the switch -classpath and -cp. On windows the seperator should be „;“ and on MacOS X it should be „:“

The code

//import the needed libs
import java.sql.*;

/**
 * @author Christian Krause
 * @version 2006-09-14
 */

public class DbConnect
{
  DbConnect()
  {
    //
  }

  /**
    * @return SQL - the SQL statement to add a new record to the databse (String)
    */
  public String populate()
  {
    String sql ="INSERT INTO testTable VALUES ("1, 'Christian', 'Krause'")";
    return sql;
  }

  /**
    * @return sql - the SQL statement to clear table (String)
    */
  public String clear()
  {
    String sql ="TRUNCATE TABLE testTable";
    return sql;
  }

  /** print some usage help */
  public static void printHelp()
  {
    System.out.println("Usage: java -classpath .;ojdbc14.jar DbConnect [option]");
    System.out.println("Possible options:");
    System.out.println("populate: populates the table "testTable"");
    System.out.println("clear: cleares the table "testTable"");
  }

  public static void main(String[] args)
  {
    DbConnect db = new DbConnect();

    /*
     * try to load the database driver
     *
     * the parameter for the common DBMS
     * Oracle: "oracle.jdbc.driver.OracleDriver"
     * MySQL: "com.mysql.jdbc.Driver"
     * PostgreSQL: "org.postgresql.Driver"
     *
     * For other DBMS ask Google... 
     */
    try
    {
      Class.forName("oracle.jdbc.driver.OracleDriver");
    }
    catch(ClassNotFoundException e)
    {
      System.out.println(e);
    }

    //try to connect to the database and execute some statements
    try
    {
      /*
       * create an new SQL connection to the database server
       * DriverManager.getConnection(String url, String user, String password)
       *
       * the url parameter for the common DBMS
       *
       * Oracle:      jdbc:oracle:thin:@host:1521:SID
       * MySQL:       jdbc:mysql://host:3306/theDatabase
       * PostgreSQL:  jdbc:postgresql:host:5432/theDatabase
       *
       * For other DBMS ask Google...  
       */
      Connection con = DriverManager.getConnection(
                        "jdbc:oracle:thin:@localhost:1521:ORCL",
                        "theUser",
                        "thePassword");
      System.out.println("Connection established!");

      //create a new statement
      Statement stmt = con.createStatement();

      //if the comandline switch was "populate"
      if(args[0].compareTo("populate") == 0)
      {
        //execute the sql statement
        stmt.executeUpdate(db.populate());
        System.out.println("testTable populated!");
      }

      //if the comandline switch was "clear"
      if(args[0].compareTo("clear") == 0)
      {
        //execute the sql statement
        stmt.executeUpdate(db.clear());
        System.out.println("testTable cleared!");
      }
      else
      {
      	printHelp();
      }
    }
    catch(SQLException sE)
    {
      System.out.println(sE);
      System.out.println("ERROR");
    }
  }
}

You can download the code here: DbConnect.java

CSS: Infobox Popup bei Weblinks

Der CSS Part sieht folgendermaßen aus:

a span {
   display: none;
}

a:hover span {
   display:block;
   position:fixed;
   top 72;
   left: 0;
   width: 124px;
   padding: 5px;
   margin: 10px;
   z-index: 10;
   color: #000;
   background: #FFF;
   font: 10px Verdana, sans-serif;
   text-align: center;
   border: 1px dashed #257;
}

Mit den Werten in Zeile 8 bis 18 müsst ihr natürlich etwas herumspielen, um es an die Gegebenheiten eurer Homepage anzupassen.

Noch eine Anmerkung zu Zeile 8: „position: fixed“ funktioniert beim Internet Explorer nicht ohne weiteres! Hier findet ihr eine schöne Anleitung, wie ihr dem IE das Fixieren von Elementen beibringt. Auf meiner Webseite habe ich einfach ein separates CSS benutzt, das „position: fixed“ durch „position: absolute“ ersetzt. Ihr könnt die beiden Dateien ja mal vergleichen: https://www.redbrick.de/css/main.css und https://www.redbrick.de/css/ie.css

Wenn ihr das Style Sheet korrekt eingebunden habt, dann könnt ihr mit folgendem Code die Popup-Box erzeugen.

Link-TextPopup-Text

Wie das ganze dann aussieht, dass seht ihr, wenn ihr mit dem Mauszeiger über die Links in den Menüs auf dieser Homepage geht (oben oder links). Die Infobox erscheint dann direkt über dem linken Menü.

FreeBSD: NFS einrichten

NFS

NFS (Network File System) dient zur Verwendung von Partitionen oder Verzeichnissen über Rechnergrenzen hinweg. Diese kleine Anleitung gibt einen nur sehr knappen und schnellen Einstieg ohne auf die vielfältigen Konfigurationsmöglichkeiten einzugehen.

In den Beispielen ist der Rechner mit der IP 192.168.1.1 der NFS-Server und alle Rechner im Netz 192.168.1.0/24 dürfen auf dessen Daten Zugreifen.

Serverseite

Auf der Seite des Servers müssen die Dienste rpcbind, mountd und nfsd laufen. Dazu fügt man folgende Zeilen der Datei /etc/rc.conf hinzu:

nfs_server_enable="YES"
nfs_server_flags="-h 192.168.1.1"

Zusätzlich müssen die zu exportierenden Verzeichnisse in der Datei /etc/exports und die IPs der erlaubten Clients angegeben werden:

/home -alldirs -network 192.168.1.0

Wichtig: Es darf nur eine Zeile pro Partition angegeben werden. Wenn mehrere Verzeichnisse von einer Partition gemountet werden sollen dürfen, dann muss man entweder wie im Beispiel den Schalter -alldirs angeben um das Mounten aller Unterverzeichnisse eines übergeordneten Verzeichnisses zu gestatten oder man gibt alle Verzeichnisse hintereinander in der gleichen Zeile an, also beispielsweise

/home/egon /home/walter /home/detlef -network 192.168.1.0

Viele weitere Informationen zu den Möglichkeiten und Beispiele gibt es in exports(5).

Das Startskript nfsd erzwingt den Start der Dienste rpcbind und mountd sofern sie nicht explizit in /etc/rc.conf aufgeführt sind. Man startet den Server also mit

/etc/rc.d/nfsd start

Bei einer Änderung der Datei /etc/exports braucht man lediglich

/etc/rc.d/mountd forcerestart

ausführen.

Clientseite

Einen NFS-Client zu konfigurieren ist wesentlich einfacher. Man fügt der Datei /etc/rc.conf die Zeile

nfs_client_enable="YES"

hinzu und bereitet das System mit

/etc/rc.d/nfsclient start

auf den Einsatz als NFS-Client vor. Schließlich trägt man nur noch eine entsprechende Zeile für das Verzeichnis in die Datei /etc/fstab ein

192.168.1.1:/home/detlef     /usr/home/detlef      nfs     rw

und mountet das Verzeichnis

mount /usr/home/detlef