JUNIT and Java

×

Overview Versions

  • Netbeans 8.2
  • JUNIT 4
  • JUNIT uses Java Reflection API to run Object Methods

Java IO sample

package fileio;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FileIO {
    private static final Logger LOGGER = Logger.getLogger( 
            Thread.currentThread().getStackTrace()[0].getClassName() );
    
    /** FileOutputStream Descriptor */        
    private FileOutputStream fos = null;
    /** OS-FileName */
    final private String fileName ;
    public FileOutputStream getFileOutputStream() { return fos; }
    public String getFileName() { return fileName; }
    
    public static void main(String[] args) {
        String writeContent = "This is my Data which needs" +
	        " to be written into the file";
        String fileName = "C:/myfile.txt";
        //LOGGER.setLevel(Level.FINEST);
        //LOGGER.setLevel(Level.SEVERE);              
        LOGGER.setLevel(Level.INFO);                  // Setting current Logger Level
        
        Locale.setDefault(new Locale("en", "EN"));  // Change Logger Language to English 
        FileIO fileIO = new FileIO(fileName);
        fileIO.doIO(fileName, writeContent);
    }
       
    public FileIO(String fileName) {
        this.fileName = fileName;
        LOGGER.info("FileIO constructor for fileName: " + fileName);
    }
/**
 * Opens, writes and closes FileOutputStream fos.
 * 

* If open was successfull both fileName and FileOutputStream Object are * stored in the related class attributes fileName, fos for later access * @param fName The fileName at OS Level * @param writeContent The message to be written to our FileOutputStream * @return true If write was successfull else return false */ public boolean doIO(String fName,String writeContent) { try { openStream(fName); // Got an excpetion if open failse int bytesWritten = writeToStream( writeContent); boolean ret = closeStream(); String loggerString = new StringBuilder("Byte written to File ") .append( this.fileName ).append(": " ).append(bytesWritten).toString(); LOGGER.info(loggerString); return true; } catch ( IOException ioe) { // Only log the Exception Message - stacktrace should be printed by low level // Exception handler. Close the stream when there is am Exception ! LOGGER.log( Level.SEVERE, ioe.toString() ); return false; } finally{ closeStream(); } } /** * Opens a FileOutputStream fos. *

* If open was successfull both fileName and FileOutputStream Object are * stored in the related class attributes fileName, fos for later access * @param fileName The fileName at OS Level * @throws IOException If stream can't be opened at OS level * @return true If Stream was opened sucessfully */ public boolean openStream (String fileName) throws IOException { String fName = fileName; FileOutputStream lfos; File file; try { if ( fName == null ) { throw new IOException("fileName can't be null"); } //Specify the file path here file = new File(fileName); lfos = new FileOutputStream(file); /* This logic will check whether the file exists or not. If the file * is not found at the specified location it would createa new file */ if (!file.exists()) { file.createNewFile(); } this.fos = lfos; // save the FileOutputStream Descriptor for later usage return true; } catch ( IOException ioe) { String errorMesg = "Error open File-Stream " + fileName; LOGGER.log( Level.SEVERE, ioe.toString(), ioe ); this.fos = null; throw new IOException(errorMesg); } } /** * Writes a String Message to already opened FileOutputStream fos. *

* Note: This methode will convert a potenial NullPointerExceptions tiggered * by either message=null or FileOutputStream fos=null to an IOExeption. * @param message The String to be written to the Stream Descriptor fos * @throws IOException If stream is not already opened at OS level or If messsage is null * @return byteCnt The number of bytes written to our opened Stream */ public int writeToStream( String message) throws IOException { try { /*String content cannot be directly written into * a file. It needs to be converted into bytes */ if (message == null ) { throw new IOException("Message should NOT be null ! "); } // don't need to check for null ! if (!(fos instanceof FileOutputStream)) { throw new IOException("FileOutputStream fos should NOT be null ! "); } byte[] bytesArray = message.getBytes(); int byteCnt = bytesArray.length; fos.write(bytesArray); fos.flush(); String loggerString = new StringBuilder("Successfully written " ) .append( byteCnt ).append(" Bytes to File: ").append(fileName).toString(); LOGGER.info(loggerString); return byteCnt; } catch (IOException ioe) { String errorMesg = "Error writing to File: " + fileName + "\n " + ioe.toString(); LOGGER.log( Level.SEVERE, ioe.toString(), ioe ); throw new IOException(errorMesg); } } /** * Closes FileOutputStream fos. *

* Note: Closing an alreday closed FileOutputStream will not throw any error * Even we get an error during close operation closeStream() methode will only log an error * without re-throwing the underlying Exception. * @return true if Stream was closed successfully */ public boolean closeStream() { try { if (fos != null) { fos.close(); } fos = null; return true; } catch (IOException ioe) { String errorMesg = "Error closing Stream " + fileName; LOGGER.log( Level.SEVERE, ioe.toString(), ioe ); return false; } } }

JUnit test for above IO sample

  • Create JUNIT test with Netbeans 8.2: Right Click on Java File -> Tools -> Create/Update Tests


    @AfterClass
    public static void tearDownClass() {
    }
    
    @Before
    public void setUp() {
         String fName = "c:/myFileTest";
        instance = new FileIO(fName);
    }
    
    @After
    public void tearDown() {
    }

    /**
     * Test of main method, of class FileIO.
     */
    @Test
    public void testMain() {
        System.out.println("-> Start Test main()");
        String[] args = null;
        FileIO.main(args);
        System.out.println("   Test main() OK");
    }

    /**
     * Test of openStream method, of class FileIO.
     */
    @Test
    public void testOpenStream() {
        System.out.println("-> Start Test openStream()");
        String fName = "c:/myFileTest";
        boolean result = false;
        // FileIO instance = new FileIO();
        boolean expResult = true;
        try {
            result = instance.openStream(fName);
        } catch ( IOException iex) {}
        
        assertTrue("Expected Test Result " + expResult +  " - Got: " +  result,  expResult==result);
        System.out.println("   Test openStream() OK!");
    }
    
       /*
        *  Open a Non-Existing File - Should fail with an IOException    
        */
    @Test (expected=IOException.class)
    public void testOpenStreamFailed() throws IOException{
        System.out.println("-> Start Test testOpenStreamFailed() - Fails with an IOException !");
        String fName = "X:/myFileTestFailed";
        boolean result = false;
        FileOutputStream expResult = null;
        result = instance.openStream(fName);
    }
    
    /**
     * Test of writeToStream method, of class FileIO.
     */
    @Test 
    public void testWriteToStream() {
        String fName = "c:/myFileTest";
        FileOutputStream fos;
        int bytesWritten = 0;
        System.out.println("-> Start Test writeToStream()");
        String message = "This is just a Test";
        int bytesToBeWritten = message.getBytes().length ;
        try {
            instance.openStream(fName);
            bytesWritten = instance.writeToStream(message);
        } catch ( IOException iex) {}
        assertTrue("Error::  Expected bytesToBeWritten: " +  bytesToBeWritten 
                + " - GOT bytesWritten " + bytesWritten ,bytesWritten == bytesToBeWritten );
        System.out.println("   Test writeToStream() OK! - bytesWritten: " + bytesWritten);

    }

    /*
        In this test we simulate a write to a Not initialized Stream Desriptor
        This Test should fail with an IOExecption     
    */
    @Test (expected=IOException.class)
    public void testWriteToStreamFailed() throws IOException {
        String fName = "c:/myFileTest";
        FileOutputStream fos = null;

        System.out.println("-> Start testWriteToStreamFailed() - Fails with IOException !");
        String message = "This is just a Test";
        int bytesToBeWritten = message.getBytes().length ;
        // instance.writeToStream should trigger an IOException
        int bytesWritten = instance.writeToStream( message);
    }
    
    /**
     * Test of closeStream method, of class FileIO.
     * We also test that closing a closed Stream doesn't throw any Exception lile in socket opes
     */
    @Test
    public void testCloseStream() {
        String fName = "c:/myFileTest";
        FileOutputStream fos = null;
        System.out.println("-> Start Test closeStream()");
        String message = "This is just a Test";
        boolean result = false;
         
        // FileIO instance = new FileIO();
        try {
            instance.openStream(fName);
            result = instance.closeStream();
          } catch ( IOException iex) {}
        assertTrue("Error: Expected true in first close !", result);
            // Now closing an alreay closed Stream
        result = instance.closeStream();
        assertTrue("Error: Expected true in 2.nd close !", result);
        System.out.println("   Test closeStream() - 2.nd Close OK No Exception !" +
            " - ret Status: " + result );
    }

    /**
     * Test of doIO method, of class FileIO.
     * Should Work and return true !
     */
    @Test
    public void testDoIO() {
        System.out.println("-> Start Test doIO()");
        String fName = "c:/myFileTest";
         String writeContent = "This is my Data which needs" +
	        " to be written into the file";
        //FileIO instance = new FileIO();
        boolean result = instance.doIO(fName,writeContent);
        assertTrue("Error: Expected true !", result);
        System.out.println("   Test doIO() OK - result " + result );
    }    
    
    /**
     * Test of doIO method, of class FileIO. 
     * This test is the most important ONE as we will test that a failed Write closes fos 
     * descriptor to avoid a resource leak. To test this does we issue an add. write after calling 
     * doIO(). This add write should fail indicating that fos descriptor was already closed
     * TestString : null
     *              -> doIO() should return false but close fos
     *              -> An addition Write Test using the closed fos shoud fail too   
     */

    @Test
    public void testDoIOFailed() throws IOException {
        System.out.println("-> Start Test testDoIOFailed() - Fails with an Assert !");
        String fName = "c:/myFileTest";
        String writeContent = null;
        //FileIO instance = new FileIO();
        boolean result = instance.doIO(fName,writeContent);
        assertFalse("Error: Expected false !", result);
            // As we can get the Stream closed status form FileOutputStream object we start a test
            // write. Note: 
            // After a failure the Stream should be closed - we expect the the next write to fail !
        writeContent = "This WRITE should NOT Work";
        int bytesToBeWritten = writeContent.getBytes().length;
        int bytesWritten = -1;
        try {
            bytesWritten = instance.writeToStream( writeContent);
        } catch ( IOException e) {}
        assertFalse("This Write should fail - as the FOS descpriptor should be closed before!", bytesToBeWritten == bytesWritten );
    }    
    
    /* 
        Writing a null Message should reurn an IOException and Not a java.lang.NullPointerException 
    */
    @Test
    public void testWriteFailed() throws IOException{
        String fName = "c:/myFileTest";
        FileOutputStream fd;
        String message = null;
        int bytesToBeWritten = -1;
        int bytesWritten = -1;
        System.out.println("-> Start Test testWriteFailed() - Catches IOException !");
       
        instance.openStream(fName);
        fd = instance.getFileOutputStream();
        assertTrue(fd instanceof FileOutputStream);
     
        try {
            bytesWritten = instance.writeToStream( message);
        } catch ( IOException iex) {} 
        
        //  This Test raises an java.io.IOException: Message should NOT be null at all -
        // > bytesWritten remain unchanged 
        assertTrue("Error::  Expected bytesToBeWritten: " +  bytesToBeWritten 
                + " - GOT bytesWritten " + bytesWritten ,bytesWritten == bytesToBeWritten );
 
        boolean closeResult = instance.closeStream();
        assertTrue("Error: Expected true !", closeResult);       
        System.out.println("   Test testWriteFailed()  OK "  );
    }    
}

JUNIT Test Output

-> Start Test writeToStream()
   Test writeToStream() OK! - bytesWritten: 19
-> Start testWriteToStreamFailed() - Fails with IOException !
-> Start Test doIO()
   Test doIO() OK - result true
-> Start Test main()
   Test main() OK
-> Start Test closeStream()
   Test closeStream() - 2.nd Close OK No Exception ! - ret Status: true
-> Start Test openStream()
   Test openStream() OK!
-> Start Test testDoIOFailed() - Fails with an Assert !
-> Start Test testWriteFailed() - Catches IOException !
   Test testWriteFailed()  OK 
-> Start Test testOpenStreamFailed() - Fails with an IOException !
Mär 30, 2018 1:52:42 PM fileio.FileIO 
INFORMATION: FileIO constructor for fileName: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO writeToStream
INFORMATION: Successfully written 19 Bytes to File: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO 
INFORMATION: FileIO constructor for fileName: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO writeToStream
SCHWERWIEGEND: java.io.IOException: FileOutputStream fos should NOT be null ! 
java.io.IOException: FileOutputStream fos should NOT be null ! 
	at fileio.FileIO.writeToStream(FileIO.java:122)
	at fileio.FileIOTest.testWriteToStreamFailed(FileIOTest.java:114)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	...

Mär 30, 2018 1:52:42 PM fileio.FileIO 
INFORMATION: FileIO constructor for fileName: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO writeToStream
INFORMATION: Successfully written 55 Bytes to File: c:/myFileTest
Mär 30, 2018 1:52:42 PM fileio.FileIO doIO
INFORMATION: Byte written to File  c:/myFileTest: 55
Mär 30, 2018 1:52:42 PM fileio.FileIO 
INFORMATION: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: C:/myfile.txt
Mar 30, 2018 1:52:42 PM fileio.FileIO writeToStream
INFO: Successfully written 55 Bytes to File: C:/myfile.txt
Mar 30, 2018 1:52:42 PM fileio.FileIO doIO
INFO: Byte written to File  C:/myfile.txt: 55
Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO writeToStream
SEVERE: java.io.IOException: Message should NOT be null ! 
java.io.IOException: Message should NOT be null ! 
	at fileio.FileIO.writeToStream(FileIO.java:119)
	at fileio.FileIO.doIO(FileIO.java:51)
	at fileio.FileIOTest.testDoIOFailed(FileIOTest.java:173)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	...

Mar 30, 2018 1:52:42 PM fileio.FileIO doIO
SEVERE: java.io.IOException: Error writing to File: c:/myFileTest
  java.io.IOException: Message should NOT be null ! 
Mar 30, 2018 1:52:42 PM fileio.FileIO writeToStream
SEVERE: java.io.IOException: FileOutputStream fos should NOT be null ! 
java.io.IOException: FileOutputStream fos should NOT be null ! 
	at fileio.FileIO.writeToStream(FileIO.java:122)
	at fileio.FileIOTest.testDoIOFailed(FileIOTest.java:182)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	..

Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO writeToStream
SEVERE: java.io.IOException: Message should NOT be null ! 
java.io.IOException: Message should NOT be null ! 
	at fileio.FileIO.writeToStream(FileIO.java:119)
	at fileio.FileIOTest.testWriteFailed(FileIOTest.java:204)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	...

Mar 30, 2018 1:52:42 PM fileio.FileIO 
INFO: FileIO constructor for fileName: c:/myFileTest
Mar 30, 2018 1:52:42 PM fileio.FileIO openStream
SEVERE: java.io.FileNotFoundException: X:\myFileTestFailed (Das System kann den angegebenen Pfad nicht finden)
java.io.FileNotFoundException: X:\myFileTestFailed (Das System kann den angegebenen Pfad nicht finden)
	at java.io.FileOutputStream.open0(Native Method)
	at java.io.FileOutputStream.open(FileOutputStream.java:270)
	at java.io.FileOutputStream.(FileOutputStream.java:213)
	at java.io.FileOutputStream.(FileOutputStream.java:162)
	at fileio.FileIO.openStream(FileIO.java:87)
	at fileio.FileIOTest.testOpenStreamFailed(FileIOTest.java:77)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        ...

Using PHPUnit

×

Installation Directories and Software Versions

  • PHP was used from our XAMPP installation at: d:\xampp\php;
  • PHPUnit Installation Direcotory: D:\PHP\phpunit;
  • Windows 7
  • NetBeans 8.2
  • PHP 5.5.15
  • PHPUnit 4.8.36
  • phpunit-skelgen-1.2.1.

Install PHPUnit on Windows7

Verify your PHP version from your XAMPP install on Windows

D:\PHP\phpunit>  d:\xampp\php\php.exe --version
PHP 5.5.15 (cli) (built: Jul 23 2014 15:05:09)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    with Xdebug v2.2.3, Copyright (c) 2002-2013, by Derick Rethans

Download PHPUnit and phpunit-skelgen package

Packages selected for download based on my PHP 5.5.15 version

  • phpunit-4.8.36.phar
  • phpunit-skelgen-1.2.1.phar
  • Directory location for PHPUnit files: D:\PHP\phpunit

Rename/Copy files

  • phpunit-4.8.36.phar -> phpunit.phar
  • phpunit-skelgen-1.2.1.phar -> phpunit-skelgen.phar

Create a new PHPUnit Command File

  • D:\PHP\phpunit> echo @php “%~dp0phpunit.phar” %* > phpunit.cmd

Modify your Windows Path varaible and verify your installation

Add to your windows PATH:   D:\PHP\phpunit;d:\xampp\php; ....

Finally verify the PHPUnit installation 
D:\Users\helmut> phpunit --version
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.

Run a PHPUnit Sample from the Command Line

Directory structure matches Netbeans Project structure

 * Directory structure:
 * ├── PhpUnitTest
 *         ├── Calculator.php
 *         ├── tests
 *               ├── bootstrap.php
 *               ├── CalculatorTest.php

Calculator.php our PHP test class

class Calculator
{
    /**
     * @assert (0, 0) == 0
     * @assert (0, 1) == 1
     * @assert (1, 0) == 1
     * @assert (1, 1) == 2
     * @assert (1, 2) == 4
     */
    public function add($a, $b)
    {
        return $a + $b;
    }
}

bootstrap.php our PHP class to autoload PHP classes for testing

chdir("..");                // Note our tests directory is located just below our real PHP files  
echo "Current Working Directory:: " . getcwd() . "\n";
class Autoloader{
    public static function register(){
        //echo "Inside Register ..\n";
        spl_autoload_register(function ($class) {
            $file = str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
            if (file_exists($file)) {
                require $file;
                echo "+++ Autoload of PHP File:: " . $file . "\n";
                return true;
            }
            return false;
        });
    }
}
Autoloader::register();

Create the test class using phpunit-skelgen.phar

D:\xampp\htdocs\tc\PhpUnitTest> php \php\phpunit\phpunit-skelgen.phar --test Calculator
PHPUnit Skeleton Generator 1.2.1 by Sebastian Bergmann.
Wrote skeleton for "CalculatorTest" to "D:\xampp\htdocs\tc\PhpUnitTest\CalculatorTest.php".

Copy CalculatorTest.php  to the tests directory 
D:\xampp\htdocs\tc\PhpUnitTest> copy CalculatorTest.php tests
tests\CalculatorTest.php überschreiben? (Ja/Nein/Alle): ja

Test class generated by phpunit-skelgen.phar

/**
 * Generated by PHPUnit_SkeletonGenerator 1.2.1 on 2018-03-04 at 12:37:11.
 */
class CalculatorTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var Calculator
     */
    protected $object;

    /**
     * Sets up the fixture, for example, opens a network connection.
     * This method is called before a test is executed.
     */
    protected function setUp()
    {
        $this->object = new Calculator;
    }

    /**
     * Tears down the fixture, for example, closes a network connection.
     * This method is called after a test is executed.
     */
    protected function tearDown()
    {
    }

    /**
     * Generated from @assert (0, 0) == 0.
     *
     * @covers Calculator::add
     */
    public function testAdd()
    {
        $this->assertEquals(
          0,
          $this->object->add(0, 0)
        );
    }

    /**
     * Generated from @assert (0, 1) == 1.
     *
     * @covers Calculator::add
     */
    public function testAdd2()
    {
        $this->assertEquals(
          1,
          $this->object->add(0, 1)
        );
    }

    /**
     * Generated from @assert (1, 0) == 1.
     *
     * @covers Calculator::add
     */
    public function testAdd3()
    {
        $this->assertEquals(
          1,
          $this->object->add(1, 0)
        );
    }

    /**
     * Generated from @assert (1, 1) == 2.
     *
     * @covers Calculator::add
     */
    public function testAdd4()
    {
        $this->assertEquals(
          2,
          $this->object->add(1, 1)
        );
    }

    /**
     * Generated from @assert (1, 2) == 4.
     *
     * @covers Calculator::add
     */
    public function testAdd5()
    {
        $this->assertEquals(
          4,
          $this->object->add(1, 2)
        );
    }
}

Run the php Unit test

D:\xampp\htdocs\tc\PhpUnitTest\tests> phpunit --bootstrap bootstrap.php CalculatorTest.php 
Current Working Directory:: D:\xampp\htdocs\tc\PhpUnitTest
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.

.
+++ Autoload of PHP File:: Calculator.php
...F

Time: 237 ms, Memory: 9.50MB

There was 1 failure:

1) CalculatorTest::testAdd5
Failed asserting that 3 matches expected 4.

D:\xampp\htdocs\tc\PhpUnitTest\tests\CalculatorTest.php:91

FAILURES!
Tests: 5, Assertions: 5, Failures: 1.

Return Codes from phpUnit

* PHPUnit Return Codes:   
 * .   Printed when the test succeeds.
 * F   Printed when an assertion fails while running the test method.
 * E   Printed when an error occurs while running the test method.
 * R   Printed when the test has been marked as risky (see Chapter 6).
 * S   Printed when the test has been skipped (see Chapter 7).
 * I   Printed when the test is marked as being incomplete or not yet implemented (see Chapter 7).      

PHPUnit and Netbeans Integration

Generic setup for PHPUnit within NetBeans IDE

Tools -> Option -> PHP -> PHP Framework -> PHPUnit
Image phpunit_img1.jpg  NOT Found

Create a new PHP project with the above Source for calcualater.php

Setup PHPUnit as test Provider

Right Click Project [ PhpUnitTest3] -> Properties -> Testing -> Add Folder
Image phpunit_img2.jpg  NOT Found

Create the PHP Test Classes

Right Click on Calculator.php -> Tools -> Create/Update Tests
Image phpunit_img3.jpg  NOT Found
 
Netbeans should create  CalculatorTest.php in out tests directory by running: 
"D:\xampp\php\php.exe" "D:\PHP\phpunit\phpunit-skelgen.phar" "--test" "--" "Calculator" 
    "D:\xampp\htdocs\PhpUnitTest3\Calculator.php" "CalculatorTest" "D:\xampp\htdocs\PhpUnitTest3\tests\CalculatorTest.php"
PHPUnit Skeleton Generator 1.2.1 by Sebastian Bergmann.

Wrote skeleton for "CalculatorTest" to "D:\xampp\htdocs\PhpUnitTest3\tests\CalculatorTest.php".  

Copy above bootstrap.php to our test folder and modify PHPUnit settings

Right Click Project [ PhpUnitTest3] -> Properties -> PHPUnit
Image phpunit_img4.jpg  NOT Found
Project Files and Directories sould now look like: 
* Directory structure:
 * ├── PhpUnitTest
 *         ├── Calculator.php
 *         ├── tests
 *               ├── bootstrap.php
 *               ├── CalculatorTest.php

Finally run PHPUnit tests

Right Click Calculator.php -> Test
Image phpunit_img5.jpg  NOT Found

Using Promises

×

About Promise

How Promises Work

A promise is an object which can be returned synchronously from an asynchronous function.
It will be in one of 3 possible states:

  • Fulfilled: onFulfilled() will be called (e.g., resolve() was called)
  • Rejected: onRejected() will be called (e.g., reject() was called)
  • Pending: not yet fulfilled or rejected

Promises following the spec must follow a specific set of rules:

  • A promise or “thenable” is an object that supplies a standard-compliant .then() method.
  • A pending promise may transition into a fulfilled or rejected state.
  • A fulfilled or rejected promise is settled, and must not transition into any other state.
  • Once a promise is settled, it must have a value (which may be undefined). That value must not change.
  • A Promise can be resolved or rejected, exclusively and only once.
  • A call to promise.then returns a promise, so that we can call the next promise
  • A value returned by a .then handler is immediately passed to the next handler
  • If the returned value is a promise, then the further execution is suspended until it settles.
  • A fetch() promise will reject with a TypeError when a network error is encountered or CORS is misconfigured on the server side
  • By default, fetch won’t send or receive any cookies from the server

Chained Promises

Chained Promises Sample

function testMe(myUrl, test, dataError) {
    dumpMessage("Testing Promise Chaining: "  + test, false);
    let url = myUrl;
    fetch(url)                           // fetch returns a promise       
        .then(response => {              // Our Success Handler returns response Object 
            if(response.ok) {
                if ( dataError) {        // Just for testing - Mimicking a Data Proessing Error
                    throw new Error('Data Processing Error');
                }  
                return response.json();
            }
            throw new Error('Network response was not ok  at Chain Level 1');
        })  // Catches Exception for our Success Handler and for our Reject Handler 
    .catch(e => { 
        dumpMessage("Exception at Chain Level 1  : " + e,true );  
        throw new Error('Initial Fetch failed for URL: ' + url); 
    })
    .then(jsonData => { dumpMessage("ID: " + jsonData.id + " - name : " + jsonData.name,false ); return(jsonData.name);} )
    .then( (user) => {  dumpMessage("Username: " + user, false);  return fetch("https://api.github.com/users/"+user ); })
        // Load the response as json
    .then(response => response.json())     
        // Show the avatar image (githubUser.avatar_url) for 3 seconds (maybe animate it)
    .then(githubUser => {
        dumpMessage("Displaying Github Avatar Image for 3 seconds!", false);  
        let img = document.createElement('img');
        img.src = githubUser.avatar_url;
        img.className = "promise-avatar-example";
        document.body.append(img);

        setTimeout(() => {
            img.remove();
            dumpMessage("Removed Github Avatar Image !", false);
        }, 3000); // (*)
    })
    .catch(err => {             // Catch all Hanlder return true/false for retry logic 
        dumpMessage("CatchAll Error-handler: " + err, true);
        });
} 

Promises and Error Handling

Overview

Pomisess Error Handling Diagram
Image promise_img1.jpg NOT Found

Handle Errors – Pattern 1


save().then(
  handleSuccess,
  handleError
);


  • Problem Exceptions in handleSuccess() are not catched

Handle Errors – Pattern 2


save()
  .then(handleSuccess)
  .catch(handleError)


Sample:
 fetch(url)                           // fetch returns a promise       
        .then(response => {              // Our Success Handler returns response Object 
            if(response.ok) {
                if ( dataError) {        // Just for testing - Mimicking a Data Proessing Error
                    throw new Error('Data Processing Error');
                }  
                return response.json();
            }
            throw new Error('Network response was not ok  at Chain Level 1');
        })  // Catches Exception for our Success Handler and for our Reject Handler 
    .catch(e => { 
        dumpMessage("Exception at Chain Level 1  : " + e,true );  
        throw new Error('Initial Fetch failed for URL: ' + url); 
    })
    .then(jsonData => { dumpMessage("ID: " + jsonData.id + " - name : " + jsonData.name,false ); return(jsonData.name);} )
    ...

Handle Errors – Pattern 3


save()
  .then(
    handleSuccess,
    handleNetworkError    -> Handle and Fix Network Error
  )
  .catch(handleProgrammerError) -> Handle anf Fix ProgamError in handleSucessFunction


Sample:
    fetch(url)                      
        .then(response => {              // Our Success Handler 
            if(response.ok) {
                if ( dataError) {        // Mimicking a Data Proessing Error
                    throw new Error('Data Processing Error');
                }  
                return response.json();
            }
            throw new Error('Network response was not ok.');
        },      
        err => {    // Now we handle the error (rejection reason)
            dumpMessage("Handle error (rejection reason): " + err,true );  
               // Create a Dummy object
            dumpMessage("Create a Default Object to Finish Promise Chain");    
            myObj = { "name":"hhutzler", "id":999 };
            return myObj;
        } )
        .catch(e => { dumpMessage("Processing Error Chaining at Level 1  : " + e,true );  
            dumpMessage("Create a Default Object to Finish Promise Chain");    
            myObj = { "name":"hhutzler", "id":999 };
            return myObj;                   
        })
            //        ,        // Now we handle the error (rejection reason)
            //e => { dumpMessage("Initial Fetch Error: " + e,true );  throw new Error('Initial Fetch Error for URL' + url); } )
            //.then(response =>  response.json() )
    .then(jsonData => { dumpMessage("ID: " + jsonData.id + " - name : " + jsonData.name,false ); return(jsonData.name);} )
    ....

Reference

CORS Details

Setup

  • Html Page was loaded from: localhost
  • PHP file was loaded from: http://hhutzler.de

JavaScript Code

console.log("Testing Promise Chaining by Returning New Promises");
fetch("http://hhutzler.de/myID.php")
  .then(response =>  response.json() )
  .then(jsonData => { console.log("ID returned by node-fetch Module : " + jsonData.id + " - name : " + jsonData.name );} );

PHP Code


$myObj = new stdClass();
$myObj->id=999;
$myObj->name = "hhutzler";
$myObj->city = "Sattelmanmsburg";

$myJSON = json_encode($myObj);

echo $myJSON;

Expected CORS Error

 
Failed to load http://hhutzler.de/myID_NW.php: No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'http://localhost' is therefore not allowed access. 
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

FIX – Add Access-Control-Allow-Origin to the PHP File

 
header('Access-Control-Allow-Origin: *'); 

$myObj = new stdClass();
$myObj->id=999;
$myObj->name = "hhutzler";
$myObj->city = "Sattelmanmsburg";

$myJSON = json_encode($myObj);

echo $myJSON;

Running my first Node.js project with Netbeans

×

Node.js Overview

Node.js processing model

  • Follows single threaded even loop processing model which can handle more and more concurrent requests easily
  • Another important point to keep in mind that Node.js architecture has two types of threads

Main Thread (Single Thread)

  • Called as internal thread as well, all the non I/O blocking requests are assigned using Main thread

Worker Thread(s)

  • Used for assigning blocking I/O heavy requests

Here are the details on how the single threaded event loop based processing works

  • Client sends the request to web sever
  • Node.js web server receives client requests from different clients, puts them into a queue. This queue is called event queue
  • Node.js has an internal component called event loop which runs the loop on event queue, assigns the request to a single thread if the request is non-blocking
  • In case of blocking (I/O heavy) request, event loop will assign this to worker thread
  • While worker thread is processing the request, event loop will continue to process other requests available in event queue

Node.js and Standard Webserver Flow-Diagramms

Node.js Flow Diagram
Image nodejs_img1.jpg NOT Found
Standard Webserver Flow Diagram
Image nodejs_img2.jpg NOT Found

My First Node.js Web Application

How it works ?

  • Netbeans runs our Code in 2 Steps
  • Step1: Netbeans start a nodejs server process to execute HTTP server Code
  • –> Our HTTP server is now listening on port : 9900
  • Step2: Netbeans starts a Chrome Browser Windows and connects to Port 9900
  • –> Our Browser display the Content provided by our Http Server

Run a first Node.js Project

Setup a Node.js project properties within Netbeans

Step 1 : Configure Netbeans Project Run Methode Step 2 : Configure Node.js Properties
Image nodejs_img1.jpg NOT Found Image nodejs_img2.jpg NOT Found

Add the following Code to main.js

const http = require('http');
const port = 9900;

const requestHandler = (request, response) => {
    let funcName = "requestHandler";
    if (request.method === 'GET' && request.url === '/' ){
        dumpMessage(funcName, "Request Method: GET - request URL: " + request.url);
        response.writeHead(200, {"Content-Type": "text/html"});
        response.end('Hello Node.js Server - at:  ' + getTime() + '!');
    }
};

const server = http.createServer(requestHandler);

server.listen(port, (err) => {
    let funcName = "server.listen";
    if (err) {
        return console.log(funcName, 'something bad happened: ' + err);
    }

  dumpMessage(funcName, 'server is listening on port: ' + port);
});

function dumpMessage(testName, mesg) {                                       
    console.log(getTime() + testName + ":: --> " + mesg);           
};
    
function getTime() {
    var ts = new Date();
    return ts.toLocaleTimeString()+ ":" + ts.getMilliseconds() + "  ";
};

Finally run the Node.js Code

Step 3 : Run the project
Image nodejs_img3.jpg NOT Found

Run above Node.js project manaully

Start the http Server

D:\xampp\htdocs\pvdata\testNodejs> "D:\Program Files\nodejs\node.exe"  "D:\xampp\htdocs\pvdata\testNodejs\main.js"
17:14:42:536  server.listen:: --> server is listening on port: 9900

Redirect your browser to the Listening Adress of our Web Server: http://localhost:9900

Browser Output
Image nodejs_img4.jpg NOT Found

Debugging a Node.js Application with Netbeans – Currently NOT working due to Netbeans Bug 271238

"D:\Program Files\nodejs\node.exe" "--debug-brk=9292" "D:\xampp\htdocs\pvdata\testNodejs\main.js"
 (node:10116) [DEP0062] DeprecationWarning: `node --debug` and `node --debug-brk` are invalid. 
Please use `node --inspect` or `node --inspect-brk` instead. 

Done.

Debugging ourNode.js Application manually

Start the node.js process with inspect-brk option

  • Enable inspector agent
  • Listen on default address and port (127.0.0.1:9229)
  • Break before user code starts
D:\xampp\htdocs\pvdata\testNodejs> node --inspect-brk main.js
Debugger listening on ws://127.0.0.1:9229/9391ed9f-a46d-4f49-bee2-b83d6dafb055
For help see https://nodejs.org/en/docs/inspector

Attach Chrome Devtools 55+ to the Node.js Debugger process

  • Open a Chrome DevTool 55+ Browser session with following URL: chrome://inspect
  • Select : Open dedicated DevTools for Node
Attach Chrome DevTools to Node.js Inspector
Image nodejs_img50.jpg NOT Found

CLI should respond with: Debugger attached

D:\xampp\htdocs\pvdata\testNodejs> node --inspect-brk main.js
Debugger listening on ws://127.0.0.1:9229/9391ed9f-a46d-4f49-bee2-b83d6dafb055
For help see https://nodejs.org/en/docs/inspector
Debugger attached.

Start Debugging

Debug Node.js by viewing Sources and setting Breakpoint
Image nodejs_img51.jpg NOT Found

Reference

Using JIRA

Overview JIRA

What is a Board ?

A board displays issues from one or more projects, giving you a flexible way of viewing, managing, and reporting on work in progress. There are two types of boards in Jira Software:

  • Scrum board: For teams that plan their work in sprints. Includes a backlog.
  • Kanban board: For teams that focus on managing and constraining their work-in-progress. Includes the option of a Kanban backlog.

What is a Epic ?

An epic captures a large body of work. It is essentially a large user story that can be broken down into a number of smaller stories. It may take several sprints to complete an epic.

What is a Sprint ?

A sprint — also known as an iteration — is a short (ideally two to four week) period in which the development team implements and delivers a discrete product increment, e.g. a working milestone version.

Introduction to JIRA & Agile Project Management

  • Introduction to JIRA & Agile Project Management
  • Install JIRA

    Downlaod JIRA

    Install JIRA on Windows 7

    D:\Program Files\Atlassian\JIRA\bin> dir \software
    20.01.2018  15:16       350.857.328  atlassian-jira-software-7.7.0-x64.exe
    
    As Administrator run: atlassian-jira-software-7.7.0-x64.exe
    Select: 
      Advanced Mode for installation 
      Ports 9080 9005     [ change Ports if needed ]
      Start as a service  [ Start JIRA as a service ]
    Login: 
      Email: 	   Helmut.Hutzler@gmail.com
      Benutzer:  Helmut.Hutzler
      Password:  .....it
    Config: 
      Running the Setup Wizard 
    

    Reference JIRA Installation

    Run JIRA on our local System JIRA

    • Note the Link below: http://localhost:9080/secure/Dashboard.jspa works ONLY on my local System !
    • Run JIRA Dashbaord

    Working with JIRA

    Create a Board using multiple Projects

    Create an Agile Board from Existing Projects
    Image jira_img1.jpg NOT Found
    Add multiple projects to the Board
    Image jira_img2.jpg NOT Found

    Add a new Project to an existing Board

    Boards -> View All Boards -> Configure -> Edit Filter Query -> Press Left Menu Button -> Add/Delete Projects
    Image jira_img3.jpg NOT Found

    Reconfigure JIRA by running Setup Wizard again

    Stop JIRA 
    D:\Program Files\Atlassian\JIRA\bin> stop-jira.bat
    
    Delete dbconfig.xml 
    D:\Program Files\Atlassian\Application Data\JIRA> del dbconfig.xml
    
    Delete Database Files 
    D:\Program Files\Atlassian\Application Data\JIRA\database> dir
    21.01.2018  10:16         2.838.528 h2db.mv.db
    21.01.2018  09:18            16.208 h2db.trace.db
                   2 Datei(en),      2.854.736 Bytes
                   2 Verzeichnis(se), 82.347.048.960 Bytes frei
    
    D:\Program Files\Atlassian\Application Data\JIRA\database> del *.db
    Möchten Sie "D:\Program Files\Atlassian\Application Data\JIRA\database\*" löschen (J/N)? j
    
    Open JIRA Baseurl to restart the configuration process: http://localhost:9080/
    

    Reference

    Using Mocha and Selenium

    Install Mocha, Chai, Selenium and Chromdriver

    Init local Repository

    D:\xampp\htdocs\pvdata\testSelenium\test> npm init
    ..
    package name: (test) testselenium
    version: (1.0.0)
    description: test Selenium and Mocha
    entry point: (googlePage.js) test_s5.js
    test command:
    git repository:
    keywords:
    author: Helmut
    license: (ISC)
    About to write to D:\xampp\htdocs\pvdata\testSelenium\test\package.json:
    
    {
      "name": "testselenium",
      "version": "1.0.0",
      "description": "test Selenium and Mocha",
      "main": "test_s5.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "Helmut",
      "license": "ISC"
    }
    
    Is this ok? (yes)
    ..
    

    Install local Nodejs Modules

    D:\xampp\htdocs\pvdata\testSelenium\test > npm install chromedriver@2.34.1 --save
    
    > chromedriver@2.34.1 install D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\chromedriver
    > node install.js
    
    Downloading https://chromedriver.storage.googleapis.com/2.34/chromedriver_win32.zip
    Saving to D:\Users\helmut\AppData\Local\Temp\chromedriver\chromedriver_win32.zip
    Received 781K...
    Received 1568K...
    Received 2352K...
    Received 3136K...
    Received 3222K total.
    Extracting zip contents
    Copying to target path D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\chromedriver\lib\chromedriver
    Done. ChromeDriver binary available at D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\chromedriver\lib\chromedriver\chromedriver.exe
    npm notice created a lockfile as package-lock.json. You should commit this file.
    npm WARN testselenium@1.0.0 No repository field.
    
    + chromedriver@2.34.1
    added 96 packages in 14.552s
    
    D:\xampp\htdocs\pvdata\testSelenium\test> npm install selenium-webdriver@3.6.0 --save
    npm WARN testselenium@1.0.0 No repository field.
    
    + selenium-webdriver@3.6.0
    added 14 packages in 4.256s
    
    D:\xampp\htdocs\pvdata\testSelenium\test> npm install chai --save
    npm WARN testselenium@1.0.0 No repository field.
    
    + chai@4.1.2
    added 7 packages in 2.129s
    

    Verify Local Module Status

    D:\xampp\htdocs\pvdata\testSelenium\test> npm  list --depth=0
    testselenium@1.0.0 D:\xampp\htdocs\pvdata\testSelenium\test
    +-- chai@4.1.2
    +-- chromedriver@2.34.1
    `-- selenium-webdriver@3.6.0
    

    Install Mocha as a Global Nodejs Module

    D:\xampp\htdocs\pvdata\testSelenium\test> npm -g install mocha@4.1
    D:\Users\helmut\AppData\Roaming\npm\mocha -> D:\Users\helmut\AppData\Roaming\npm\node_modules\mocha\bin\mocha
    D:\Users\helmut\AppData\Roaming\npm\_mocha -> D:\Users\helmut\AppData\Roaming\npm\node_modules\mocha\bin\_mocha
    + mocha@4.1.0
    updated 1 package in 4.61s
    

    Verify Global Package Status

    D:\xampp\htdocs\pvdata\testSelenium\test> npm  list --depth=0  -g
    D:\Users\helmut\AppData\Roaming\npm
    +-- eslint@4.16.0
    `-- mocha@4.1.0
    

    Testscripts

    Script: test_s4.js

    require('chromedriver');
    var assert = require('chai').assert;
    var selenium = require('selenium-webdriver');
    var test = require('selenium-webdriver/testing');
    var driver;
    var GooglePage = require('./googlePage.js');
    
    const timeOut = 15000;
     
    test.describe('Testing Google Search Page', function() {
      test.beforeEach(function() {
      	dumpMessage("-> beforeEach Hook");
        this.timeout(timeOut);
        driver = new selenium.Builder()
        	.forBrowser('chrome')
        	.build();
      	var googlePage = new GooglePage(driver);
        googlePage.view();
    
      });
      
      test.it( 'Working TestCase' , function(){  
        this.timeout(timeOut);
      	driver.getTitle().then(function(title){
      		dumpMessage("Found Page Title: " + title);
      		assert.equal("Google",title );
    	});
    	dumpMessage("--> Start Processing" ); 
    	driver.findElement(selenium.By.name('q')).sendKeys('webdriver');           // Fill in the  Search String for Google Search 
    	driver.findElement(selenium.By.name('btnK')).click();					   // Start the Google Search 	
        dumpMessage("--> Leaving Processing" ); 
      });
      
        test.it( 'Failing TestCase' , function(){  
        this.timeout(timeOut);
      	driver.getTitle().then(function(title){
      		dumpMessage("Found Page Title: " + title);
      		assert.equal("xGoogle",title );
    	});
    	dumpMessage("--> Start Processing" ); 
    	driver.findElement(selenium.By.name('q')).sendKeys('webdriver');           // Fill in the  Serach String to the 
    	driver.findElement(selenium.By.name('btnK')).click();					   	// Start the Google Search 	
        dumpMessage("--> Leaving Processing" ); 
      });
                
      test.afterEach(function() {
      	  var promise;
      	  var waitTime = 2000;       // Keep the browser window 2 seconds open before calling driver.quit()
      	  this.timeout(10000);       // Increase Timeout ot avoid Error: Timeout of 2000ms exceeded. 
    								 // If returning a Promise, ensure it resolves.        
        	promise = new Promise(function(resolve, reject){
            	setTimeout(function(){
               		dumpMessage("-> afterEach Hook Promise called - WaitTime: " +  waitTime );
               		driver.quit();
                	resolve();
            	}, waitTime);
     		});
        	// mocha will wait for the promise to be resolved before exiting
        	return promise;      		
      	dumpMessage("-> afterEach Hook");
      });
    
    });
    															 		// Helper Functions 							
    function dumpMessage(mesg) {                                        // console.log at top level will create a undefined message
    	console.log(getTime() + mesg);                                  // Provide a wrapper function which returns some data 
    	return "---------------------------------------------------";	
    }
    
    function getTime() {
    	var ts = new Date();
        return ts.toLocaleTimeString()+ ":" + ts.getMilliseconds() + "  ";
    }
    

    Script: googlePage.js

    var webdriver = require('selenium-webdriver');
     
    GooglePage = function GooglePage(driver) {
      this.driver = driver;
      this.url = "http://www.google.com/ncr";
    };
     
    GooglePage.prototype.view = function() {
      this.driver.get(this.url);
      return webdriver.promise.fulfilled(true);
    };
     
    module.exports = GooglePage;                     // export the module so in an be imported with the require syntax
    

    Running the Mocha/Selenium Testcase

    Testcase Overview

    • Testcase consists out of 2 tests !
    • Both tests starts and closes the Chromedriver
    • Testcase 1 should work !
    • Testcase 2 should fail !

    Testcase Details

    Command: mocha test_s5.js
    Image mocha_img4.jpg NOT Found

    A more complete Testcase

    NetBeans Output

    Press F6 in Netbeans to Start Test Scripts
    Image mocha_img10.jpg NOT Found

    Reference

    Using Selenium Webdriver with Javascript

    Introduction Selenium-WebDriver

    • The WebDriverJS library uses a promise manager to ease the pain of working with a purely asynchronous API
    • Rather than writing a long chain of promises allows you to write synchronous code by using a blocking API

    Sample using a chain of promises [asynchronous Mode]

    const {Builder, By, until} = require('selenium-webdriver');
    new Builder()
        .forBrowser('firefox')
        .build()
        .then(driver => {
          return driver.get('http://www.google.com/ncr')
            .then(_ => driver.findElement(By.name('q')).sendKeys('webdriver'))
            .then(_ => driver.findElement(By.name('btnK')).click())
            .then(_ => driver.wait(until.titleIs('webdriver - Google Search'), 1000))
            .then(_ => driver.quit());
        });
    

    Sample using a chain of promises [synchronous Mode]

    const {Builder, By, until} = require('selenium-webdriver');
    
    let driver = new Builder()
        .forBrowser('firefox')
        .build();
    
    driver.get('http://www.google.com/ncr');
    driver.findElement(By.name('q')).sendKeys('webdriver');
    driver.findElement(By.name('btnK')).click();
    driver.wait(until.titleIs('webdriver - Google Search'), 1000);
    driver.quit();
    

    Understanding the Promises Chain

    Selenium Code:
    driver.sleep(4000);                       // Let the chromedriver Browser open for 4 seconds to review results
    driver.quit();
    
    Logger Output:
    [2018-01-17T09:37:13Z] [WARNING] [promise.ControlFlow] Detected scheduling of an unchained task.
        When the promise manager is disabled, unchained tasks will not wait for
        previously scheduled tasks to finish before starting to execute.
        New task: Task: WebDriver.quit()
            at thenableWebDriverProxy.schedule (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\webdriver.js:807:17)
            at thenableWebDriverProxy.quit (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\webdriver.js:840:23)
            at Object. (D:\xampp\htdocs\pvdata\testSelenium\test\testSelenium.js:31:8)
            at Module._compile (module.js:635:30)
            at Object.Module._extensions..js (module.js:646:10)
            at Module.load (module.js:554:32)
            at tryModuleLoad (module.js:497:12)
            at Function.Module._load (module.js:489:3)
            at Function.Module.runMain (module.js:676:10)
            at startup (bootstrap_node.js:187:16)
        Previous task: Task: WebDriver.sleep(4000)
            at ControlFlow.timeout (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\promise.js:2510:17)
            at thenableWebDriverProxy.sleep (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\webdriver.js:956:23)
            at Object. (D:\xampp\htdocs\pvdata\testSelenium\test\testSelenium.js:30:8)
            at Module._compile (module.js:635:30)
            at Object.Module._extensions..js (module.js:646:10)
            at Module.load (module.js:554:32)
            at tryModuleLoad (module.js:497:12)
            at Function.Module._load (module.js:489:3)
            at Function.Module.runMain (module.js:676:10)
            at startup (bootstrap_node.js:187:16)                                                                                                                                                              
    
    • The Task: WebDriver.quit() is scheduled after WebDriver.sleep(4000);
    • This is called the Promises Chain

    Logging with Webdriver-Selenium

    Selenium Code: 
    var {Builder, By, until, logging } = require('selenium-webdriver');
    //
    // Enable Logging 
    logging.installConsoleHandler();
    logging.getLogger('promise.ControlFlow').setLevel(logging.Level.ALL);
    
    Logger Output:
            at Function.Module._load (module.js:489:3)
    [2018-01-17T09:37:13Z] [WARNING] [promise.ControlFlow] Detected scheduling of an unchained task.
        When the promise manager is disabled, unchained tasks will not wait for
        previously scheduled tasks to finish before starting to execute.
        New task: Task: WebDriver.getTitle()
            at thenableWebDriverProxy.schedule (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\webdriver.js:807:17)
            at thenableWebDriverProxy.getTitle (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\webdriver.js:1000:17)
            at Object. (D:\xampp\htdocs\pvdata\testSelenium\test\testSelenium.js:12:8)
            at Module._compile (module.js:635:30)
            at Object.Module._extensions..js (module.js:646:10)
            at Module.load (module.js:554:32)
            at tryModuleLoad (module.js:497:12)
            at Function.Module._load (module.js:489:3)
            at Function.Module.runMain (module.js:676:10)
            at startup (bootstrap_node.js:187:16)
        Previous task: Task: WebDriver.navigate().to(http://www.google.com/ncr)
            at thenableWebDriverProxy.schedule (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\webdriver.js:807:17)
            at Navigation.to (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\webdriver.js:1133:25)
            at thenableWebDriverProxy.get (D:\xampp\htdocs\pvdata\testSelenium\test\node_modules\selenium-webdriver\lib\webdriver.js:988:28)
            at Object. (D:\xampp\htdocs\pvdata\testSelenium\test\testSelenium.js:11:8)
            at Module._compile (module.js:635:30)
            at Object.Module._extensions..js (module.js:646:10)
            at Module.load (module.js:554:32)
            at tryModuleLoad (module.js:497:12)
            at Function.Module._load (module.js:489:3)
            at Function.Module.runMain (module.js:676:10)
    

    Install Selenium-WebDriver /Chromedriver locally

    • npm install selenium-webdriver@3.6.0
    • npm install chromedriver@2.34.1

    Verify Installation

    D:\xampp\htdocs\pvdata\testSelenium\test>npm list --depth=0
    D:\xampp\htdocs\pvdata\testSelenium\test
    +-- chromedriver@2.34.1
    `-- selenium-webdriver@3.6.0
    

    Testing a Google Search with Selenium Webdriver

    Create a JavaScript file testSelenium.js

    require('chromedriver');
    var {Builder, By, until, logging } = require('selenium-webdriver');
    //
    // Enable Logging 
    // logging.installConsoleHandler();
    //logging.getLogger('promise.ControlFlow').setLevel(logging.Level.ALL);
    
    var  driver = new Builder()
        .forBrowser('chrome')
        .build();
    dumpMessage( "--- Script Start ---");
    
    driver.get('http://www.google.com/ncr');
    driver.getTitle().then(function (titleName ) {	dumpMessage("Initial Google Page load - Page Title: ---" + titleName + "---" ); });
    
    driver.findElement(By.name('q')).sendKeys('webdriver');            	// Fill in the  Serach String to the 
    driver.findElement(By.name('btnK')).click();					   	// Star the Google Searcht 	
    
    var searchTitle = 'webdriver - Google Search';                    	// The New Page Title  
    driver.wait(until.titleIs(searchTitle), 10000)						// Wait Google Search List becomes availabe
    	.then(function (titleName ) { console.log(getTime() + "Title Element now Visible in DOM ? : " + titleName)});
    
    var xPathElem =  '//*[@id="rso"]/div/div/div[1]/div/div/h3/a';      // xPAth to the  first Item from Google Search Results  
    driver.wait(until.elementLocated( { xpath: xPathElem }),20000)      // Wait until Goggle Search Results becomes available 
    	.then(function () { dumpMessage("XPath wait finished : Element  Found in DOM - xPath :  " + xPathElem );
    		}); 
    
    driver.findElement( { xpath: xPathElem }).click()                   // Click ON the for Search Result   
    	.then(function (  ) { dumpMessage("xPath  Element  Found in DOM: Triggering a Click Event on first Element of Google Search List !" );
    		});
    			
    driver.sleep(4000);                                               	// Let the chromedriver Browser open for 4 seconds to review results
    driver.quit();                                                    	// Finally Quit the driver 
    
    dumpMessage( "--- Script End ---");                              	// Note as all functions are async wer 
    
    															 		// Helper Functions 							
    function dumpMessage(mesg) {                                        // console.log at top level will create a undefined message
    	console.log(getTime() + mesg);                                  // Provide a wrapper function which returns some data 
    	return "---------------------------------------------------";	
    }
    
    function getTime() {
    	var ts = new Date();
        return ts.toLocaleTimeString()+ ":" + ts.getMilliseconds() + "  ";
    }
    

    Run first Selenium-Webdriver Script: testSelenium.js

    D:\xampp\htdocs\pvdata\testSelenium\test> node testSelenium.js
    

    Script Output

    D:\xampp\htdocs\pvdata\testSelenium\test> node testSelenium.js
    10:40:29:745  --- Script Start ---
    10:40:29:745  --- Script End ---
    
    DevTools listening on ws://127.0.0.1:12790/devtools/browser/aa1d4440-591b-45dd-8332-f590848ec58c
    10:40:34:359  Initial Google Page load - Page Title: ---Google---
    10:40:35:173  Title Element now Visible in DOM ? : true
    10:40:35:187  XPath wait finished : Element  Found in DOM - xPath :  //*[@id="rso"]/div/div/div[1]/div/div/h3/a
    10:40:36:320  xPath  Element  Found in DOM: Triggering a Click Event on first Element of Google Search List !
    

    Understanding the Script Output

    • The Script end is reached in less then 1ms [ due to the Asyn Mode of Node.js ]
    • All driver calls are scheduled via chains of promises for later execution
    • After about 5 seconds the ChromeDriver is started and initial Google Search Mask gets displayed [ Page Title : Google ]
    • About 1 second later the Google Search List gets displayed [ Page Title: webdriver Google-Search ]
    • Again 1 second later the 1 entry of our Google Search List gets displayed

    Reference

    Unit Testing with Netbeans [Mocha]

    ×

    Versions used

    • Netbeans IDE 8.2
    • Mocha 4.0.1 – Our Testing Tool
    • Chai 4.1.2 – An Assert Library

    Create a HTML5 Project with Javascript Support inside Netbeans

    Create a HTML5/Javascript Project and add Javascript File main2.js to the project
    Image mocha_img0.jpg.jpg NOT Found
    • Note: exports is a node.js concept that declares the functions that your module makes available to code outside itself

    Setup Mocha as Testing Provider

    Change Project Properties for Javascript Testing
    Image mocha_img1.jpg.jpg NOT Found

    Setup Mocha/Chai [ Open a Netbeans Terminal Window]

    Initialize new Node.js Project

    
    $ cd D:\xampp\htdocs\pv\mochaTest2
    $ npm init                                                                                                                                                                                  
    This utility will walk you through creating a package.json file.
    It only covers the most common items, and tries to guess sensible defaults.
    
    See `npm help json` for definitive documentation on these fields
    and exactly what they do.
    
    Use `npm install ` afterwards to install a package and
    save it as a dependency in the package.json file.
    
    Press ^C at any time to quit.
    package name: (mochatest2) 
    version: (1.0.0) 
    description: Mocha/Chai Testing
    entry point: (index.js) main2.js
    test command: mocha
    git repository: 
    keywords: 
    author: Helmut
    license: (ISC) MIT
    About to write to D:\xampp\htdocs\pv\mochaTest2\package.json:
    
    {
      "name": "mochatest2",
      "version": "1.0.0",
      "description": "Mocha/Chai Testing",
      "main": "main2.js",
      "directories": {
        "test": "test"
      },
      "scripts": {
        "test": "mocha"
      },
      "author": "Helmut",
      "license": "MIT"
    }
    
    
    Is this ok? (yes) yes
    
    helmut@myPC /cygdrive/d/xampp/htdocs/pv/mochaTest2
    
    

    Setup Mocha and Chai in our Netbeans Project Base Directory

    helmut@myPC /cygdrive/d/xampp/htdocs/pv/mochaTest2
    $  npm install mocha                                                                                                                                                                       
    npm WARN mochatest2@1.0.0 No repository field.
    + mocha@4.0.1
    added 24 packages in 2.189s
    
    helmut@myPC /cygdrive/d/xampp/htdocs/pv/mochaTest2
    $  npm install chai                                                                                                                                                                          
    npm WARN mochatest2@1.0.0 No repository field.
    
    + chai@4.1.2
    added 7 packages in 1.304s
    

    Verify package.json – created by our previous setup steps

    helmut@myPC /cygdrive/d/xampp/htdocs/pv/mochaTest2
    $ cat   package.json 
    {
      "name": "mochatest2",
      "version": "1.0.0",
      "description": "Mocha/Chai Testing",
      "main": "main2.js",
      "directories": {
        "test": "test"
      },
      "scripts": {
        "test": "mocha"
      },
      "author": "Helmut",
      "license": "MIT",
      "dependencies": {
        "chai": "^4.1.2",
        "mocha": "^4.0.1"
      }
    }
    
    

    Create and Run Mocha testscript manually under Unit Test direcorty

    Manually run Mocha Tests via Netbeans Terminal Window
    Image mocha_img2.jpg.jpg NOT Found
    • Our test script mochaTest2.js imports the functions from Chai and main2.js via require()
    • describe()` is merely used for grouping test Tests – can be nested if needed
    • `it()` is a test case

    Finally run Neteans Unit Tests [ ALT F6]

    Open Netbeans Test Result Window to review Test Results
    Image mocha_img3.jpg.jpg NOT Found
    • Note: If Netbeans IDE hangs during Testing you may need to restart Netbeans to fix this !

    Reference

    How To Unit Testing JavaScript with Netbeans
    Mocha Homepage
    Working with package.json
    An Absolute Beginner’s Guide to Using npm
    Understanding module.exports and exports in Node.js

    Decrypt HTTPS traffic with Wireshark and Fiddler

    ×

    Using Wireshark on Windows 7 – Key Facts and Overview

    • Wireshark is a traffic analyzer, that helps you to learn how networking work and how to diagnose Network problems
    • To track SSL Traffic on Windows we use Wireshark with Session Key Logging
    • If the Browser uses the Diffie-Hellman cipher we need to disable it

    Understanding the SSL Handshake Protocol

    TLS/SSL Handshake Diagram
    Image https_img1.jpg NOT Found
    • The SSL or TLS client sends a “client hello” message that lists cryptographic information such as the SSL or TLS version and, in the client’s order of preference, the CipherSuites supported by the client
    • The SSL or TLS server responds with a “server hello” message that contains the CipherSuite chosen by the server from the list provided by the client
    • Reference:An overview of the SSL or TLS handshake
    • Note: The “server hello” is very important as it Diffie-Hellman Cipher can’t be traced !

    Disable the Diffie-Hellman Cipher for Browsers

    Disable the Diffie-Hellman Cipher for Firefox

    • Launch Firefox, navigate to “about:config” from address bar
    • Double click all the Diffie-Hellman ciphers starting with dhe or ecdhe to change the Value to false
    • Restart Firefox to take effect
    Disable the Diffie-Hellman Cipher for Firefox
    Image ssl_dh_img2.jpg NOT Found

    Disable the Diffie-Hellman Cipher for Chrome

    • View the default Cipher Suites list from the Client Hello message of Chrome
    • Append all the ciphers that contain “ECDHE” or “DHE” in hex to command line parameter:”–cipher-suite-blacklist” and launch Chrome
    • Sample: chrome.exe –cipher-suite-blacklist=0xc02b,0xc02f,0x009e,0xcc14,0xcc13,0xc00a,0xc014,0x0039,0xc009,0xc013,0x0033
    Cipher Suites (15 suites)
         Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
         Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
         Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
         Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcc14)
         Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcc13)
         Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
         Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
         Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
         Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
         Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
         Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
         Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
         Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
         Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
         Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)
    
    

    Testing SSL Decryption with Wireshark

    Setup Wireshark

    Activate Session Key Logging on Windows Action
    Image https_img1.jpg NOT Found
    • Create SSLKEYLOGFILE enviroment variable
    Image https_img2.jpg NOT Found
    • Enable SSLKEYLOGFILE for SSL Protocol
    Image https_img21.jpg NOT Found
    • If needed add add. HTTPS Ports like : Port 8443
    • Edit -> Preferences -> Protocols -> HTTP

    Run Wireshark and decrypt a TLS/SSL packet

    Run first https test against Google Website
    Image https_img3.jpg NOT Found
    • Testing against https:/gooogle.de
    • The decrypted SSL indicates that this packet was decrypted sucessfully !

    Advantages / Disadvantages using Wireshark

    Advantages Disadvantages
    A little bit complicated Very detailed Info for the complete Network Stack
    You need to know a lot of Networking Details Client must support SSLKEYLOGFILE feature
    Support only certain Browsers [ Firefox, Chrome ] and email clients [ thunderbird] No support for cURL and WordPress function like wp_get_remote() and

    Reference

    Using Fiddler

    Fiddler – How it Works

    Overview
    Image fiddler_overview.jpg NOT Found
    • To read HTTPS data Fiddler is acting like a Man-in-the-Middle
    • Fiddler is listening to following Network proxy: localhost:8888
    • On startup Fiddler registers as a WinINET-Proxy service
    • All Browsers [ like Chrrome, Firefox ] taking care of this service sends its data to the >Fiddler-Proxy first
    • Finally Fiddler sends the data to the Target Host

    Setup – Enable Decryption of SSL/HTTPS traffic

    Setup
    Image fiddler_setup.jpg NOT Found
    • Menu: Tools -> Option -> HTTPS
    • Check: X Decrypt HTTPS Traffic

    Decrypt cURL HTTPS traffic with Fiddler

    Using cUrl : add –proxy 127.0.0.1:8888 to the cUrl command
    Image fiddler_curl1.jpg NOT Found
    • Start Fiddler
      [Note Fiddler uses Portnumber: 8888 per Default ]
    • Add –proxy 127.0.0.1:8888 to your curl command
    Image fiddler_curl2.jpg NOT Found
    • Use Inspectors menu item
    • This gives as a decrypted view of the HTTPS Post Request
    • Note: Passwords and Username can now easily extracted
    • Use the RAW menu item to get details about
      HTTPS Response Request like:
      HTTP Response Code, HTTPS Header and HTTPS
      Response Body

    Decrypt WordPress HTTPS traffic for wp_remote_get()/wp_remote_post() with Fiddler

    Application Details

    Display Timelines with Fiddler

    Timeline
    Image fiddler_timeline.jpg NOT Found
    • Page load [ /pv/wr] is decoupled from the PHP processing
    • PHP processing [initWRApp.php] is triggered via Ajax Request
    • All Remote PHP processing steps [login.action, tologin.action and summaryInfo.action] runs sequentially

    Display HTTP Packet Details with Fiddler

    Step1 : Initial Page Load WebBrowser -> Local Webserver [ 192.168.1.50]
    Image fiddler_data_img1.jpg NOT Found
    • Protocal: HTTP
    • Http Get Request to load the initial Page
    Step2: Starting PHP Remote Processing WebBrowser -> Local Webserver [ 192.168.1.50]
    Image fiddler_data_img2.jpg NOT Found
    • Protocal: HTTP
    • Http Get Request to start PHP Remote Processing with wp_remote_get and wp_remote_post
    Step3: Authenticate with Username/Password against Remote Webserver Local Webserver [ 192.168.1.50] -> Remote Webserver [ 52.58.164.53:8443 ]
    Image /fiddler_data_img3.jpg NOT Found
    • Protocol: HTTPS Post
    • URL: https://52.58.164.53:8443/security!login.action
    • WordPress Function used: wp_remote_post()
    • Remote Webserver return “op.successfully” if login OK !
    • Remote Webserver return New JSESSIONID cookie if login OK !
    Step 4: Capture initial Page after Login into Remote Werbserver Local Webserver [ 192.168.1.50] -> Remote Webserver [ 52.58.164.53:8443]
    Image fiddler_data_img4.jpg NOT Found
    • Protocol: HTTPS Get
    • URL: https://52.58.164.53:8443/security!tologin.action
    • WordPress Function used: wp_remote_get()
    • Remote Webserver return Initial Webpage after successful login!
    • Remote Webserver return X-CSRF-Token which should be used for subsequent requests
    Step 5: Finally capture Data from Remote Werbserver Local Webserver [ 192.168.1.50] -> Remote Webserver [ 52.58.164.53:8443]
    Image fiddler_data_img5.jpg NOT Found
    • Protocol: HTTPS Post
    • URL: https://52.58.164.53:8443/summaryAction!querySummaryInfo.action?nodeSN=0
    • WordPress Function used: wp_remote_post()
    • Remote Webserver return Data in Json Format
    • For this request we use JSESSIONID cookie returned from Step 3
    • For this request we use X-CSRF-TOKEN returned from Step 4

    Advantages/Disadvantages using Fiddler

    Advantages Disadvantages
    Easy Setup Only HTTP/HTTP traffic can be monitored
    Support all sort of clients like cURl, PHP, Browers, Email Clients, …