CS 235 - Week 14 Lecture - 2015-11-30

**********
A TASTE of UNIT TESTING with JUnit
**********

*   unit testing - writing tests for each "unit" of
    code
    *   in Java, being very object-oriented,
        you'd write unit tests for each method in
	a class;

        (but, most testing frameworks will allow
        you to write a testing class for each class,
	writing test methods to test the methods
	of that "class under test", the class being
	tested)

    *   IDEALLY -- you write the unit tests for a method
        before you write the method

    *   TDD - test-driven development - takes this even
        further, says to write 1 test, write code to make
	that pass, write the next test, write code to
	make that pass, etc.!

   *   there are a number of unit testing frameworks
       out there -- a number that are Java-specific;

       one of the "classics" is called JUnit, and that's
       what we are introing here;

   *   junit.org has MUCH info on JUnit,
       including its API (look under the JavaDocs link
       under "Welcome"!)

       (it is not part of the Java SDK...)

       BUT it is included in many IDEs,
       including Eclipse, NetBeans, and even DrJava

*   (I hope the following is up-to-date...)
    *   to write a JUnit testing class,
        import the following:

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

    *   common naming standard -- the unit tests for
        a class Foo would be in a class named FooTest

	SO - if I wanted to write unit tests for my
	GameDie class from the Week 1 lab,
	I'd make a class GameDieTest

    *   typically, you'll declare some instances of
        the class being tested as private data fields

    *   THEN, write a method named setUp that
        instantiates these private data fields
	AND does any other setup I want to be
	done prior to EACH test method

        how does this happen?
	with the help of the above imports
	AND additional ANNOTATIONS:

	@Before

	...this annotation, usually put directly before
	this setUp method,
	means, run this BEFORE each test method

    @Before
    public void setUp() throws Exception
    {
        ... desired set up statements ...
    }

    *   for each test method,

        *   precede it with a @Test annotation,

        *   and (typically) name it starting with the
	    word test followed by (mostly) the name of the method
	    being tested (uppercase its first letter for
	    Java's traditional camelCase):

	    to test getNumRolls, you'd write testGetNumRolls
	    to test getNumSides, you'd write testGetNumSides

        *   then, put a combination of statements and
	    assert calls to test that method;

    *   the Assert class has NUMEROUS static assert methods;

        here are two:

	assertEquals - optionally first expects a string
	               describing what should happen with this
		       test,

		       then the expected value,

		       then the call being tested

		       (for double values, add an additional
		       argument -- the delta, how "close" is
		       close enough)

        assertTrue -   optionally first expects a string
	               describing what should happen with this
		       test,

                       then a boolean expression (typically
		       including a call to the method being
		       tested) that should be true if all
		       is well

        some others:
	assertFalse, assertSame, assertArrayEquals,
        assertNotSame, assertNull, assertNotEquals,
	fail

        *   junit.org has API, including package org.junit, which
	    contains Assert class, and javadoc for these
	    static assert methods;

	    ...remember, follow the JavaDocs link under
	    "Welcome"

*   CAN run from command line, BUT since this package
    is not part of standard Java SDK, there are additional
    steps to do so -- see junit.org

    *   BUT many Java IDEs include support for JUnit, built-in --
        for example, in DrJava, if you have a class and its
	JUnit test class open,

	then you can click the "Test" button (upper right) to
        run the JUnit tests, and get green, red indicators for
	methods whose assertions passed (green) and failed (red)

        *   (after class) - oh! also can run using 
            Tools->Test All Documents
	    Tools->Test Current Document

    *   (and other IDEs -- Eclipse, pretty sure NetBeans -- have even
        fancier support; 

        ...some IDEs can be set up to run unit tests
	every time you compile!

	...and some source code version systems will RUN unit tests
	on code being added, and won't allow the code to be added
	if they don't pass;) 

**********
a tiny bit more about just TWO of the (many)
options for file input/output
**********

*   reading from, writing to a file!

    *   TINY bit about this on pp. 84-85, in Chapter 3,
        of "Core Java"!

    **********
    the File class
    **********
    *   LITTLE ASIDE:
        *   this is from Volume II of "Core Java"...

        *   package java.io has MANY input/output related
            classes, mostly stream-based but even a few
	    record-based;

        *   also includes a useful class File, which
	    [from Core Java Volume II] "encapsulates
            the functionality that you will need in order to
            work with the file system on the user's machine"

        *   convenient: one of File's constructors expects a
	    String representing the name of a file,
	    and creates a File instance representing that
	    file;

        *   File includes methods that let you...

            *   delete a file
            *   create a directory
            *   list directory contents
            *   query the size of a file
            *   query when a file was last modified
            *   query if a file is readable or writable
            *   and more...

        *   NOTE: except for nuking them outright,
            you cannot modify the CONTENTS of a file
	    using File methods --
  	    you need an input or output stream for
	    that (via Scanner or PrintWriter or one
	    of MANY other classes in java.io)

**********
(back to considering a bit more on file input/output)
**********

    *   since Java 5, we have seen that we can read from interactive input
        using Scanner

        *   (recall:
	    import java.util.*;

            ...

                Scanner in = new Scanner(System.in);
                
                System.out.println("please enter a line: ");
                String enteredLine = in.nextLine();

                System.out.println("please enter an integer quantity: ");
                int enteredQuant = in.nextInt();

		...and numerous other next methods, see Scanner
                class in package java.util in Java 8 API!

            *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!
            OH -- and IS CONSIDERED GOOD PRACTICE to *close* your
	    Scanner instance when done!!

	         in.close();

            *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!  

    **********
    ANOTHER of SEVERAL ways to READ from a file in Java
    **********

    *   (why "another"? Because we used one way in the JDBC examples,
        to read the Oracle password from a file...)

    *   ...hey! you can also read from a FILE using
	Scanner! (from package java.util)

        Scanner inFile = new Scanner(new File("myFile.txt"));

        *   NOTICE: one of Scanner's constructors can take a *File*
	    class instance! That's what is being used above;

        ...and now I can use the Scanner methods to
	read from this file myFile.txt in (probably) the
	current working directory

        String nextStr = inFile.nextLine();

        *   USEFUL: Scanner includes a hasNext method, that returns
	    true if there is still something left TO read --

	    so can use this to iterate through a file's
	    contents, reading them:

            while (inFile.hasNext())
            {
                System.out.println(inFile.nextLine());
            }

        *   GOOD STYLE: close your Scanner when done:

	    inFile.close();

    **********
    ONE of SEVERAL ways to WRITE to a file in Java
    **********

    *   how about writing to a file?

        package java.io has many output stream possibilities,
	but we'll use PrintWriter

        (then we have familiar methods println, print, printf!)

        PrintWriter outStream = new PrintWriter("myFile.txt");

        *   note that PrintWriter has a constructor that just
	    expects a String representing the name of a file...

    *   then, amongst its methods are the familiar
	println, print, printf...

        ...
        outStream.println("blah");
	outStream.printf("%.3f", 37.3);

        ...

    *   GOOD STYLE: close your PrintWriter when done:

        outStream.close();

    *   ALSO NOTE: creating a PrintWriter may throw an exception
        (what if you try to create an output stream to a file
	that you aren't allowed to write to?) --

        SO, may have to put this in a try-block!

        (and remember that Exception should be a superclass or ancestor for
	all exception classes, so can catch Exception if you want a
        single complaint/action regardless of the specific exception
	thrown...)
 
        (BUT you can also check the Java 8 API, package java.io,
	PrintWriter class, and go to the PrintWriter constructor
	method to see what exceptions it MIGHT throw)
 
**********
ASIDE from AFTER CLASS 
**********
    *   (notice: if you open an existing file on
        a PrintWriter, it NUKES its current contents --
	there IS a way to open for appending,

        ...with the help of FileWriter, which includes a constructor
	whose second boolean argument determines whether the *file*
	is (true) being opened for appending, with the next write
	going at the end of the current contents, or
	(false) being opening for writing, which nukes any present
	contents,

	...AND with the help of BufferedWriter, which
http://stackoverflow.com/questions/1625234/how-to-append-text-to-an-existing-file-in-java
        recommends for use with an "expensive" writer such as FileWriter:

        PrintWriter myAppendingOut = 
            new PrintWriter(new BufferedWriter(new FileWriter("filename.txt", true)));

        *   COULD just use FileWriter, but PrintWriter has the 
            print and println methods, which FileWriter does not; 
            you'd likely use the FileWriter's
	    write method in that case;

********* (end of appending-to-a-file aside) **********

**********
how to find out: what IS the current working directory?
(when a program is running)
**********

*   what is your current working directory?
    *   from "Core Java" text, p. 84 (Chapter 3):

        "When you specify a relative file name ... the file
        is located relative to the directory in which the
        Java Virtual Machine was started"

    *   IF you are using an IDE where it is unclear
        WHERE the JVM is running --

        (important because relative file names are
        relative to the directory in which the JVM
        was started)

        you can find out what this is -- if needed/desired -- with:

        String dir = System.getProperty("user.dir");

    *   (in a pinch, you can try absolute path names...)

    ********
    ASIDE from Week 14 Lab (with thanks to P. Abbey!)
    changing DrJava working directory on Windows:
    ********

    If you are running DrJava on Windows, the following
    should allow you to change the current working directory:

    *   From the Edit menu, select Preferences
        *   (a Preferences dialog should open up)

    *   From the Categories list on the left, select Interactions Pane

    *   Change the Interactions Working Directory to your desired
        working directory

    *   click Apply button, then OK button

    *   (when you next compile, Interactions window should show
        the newly-selected current working directory --
        and files being read, written should be in this
        directory...)

**********
TINY taste of Java collections/generics

[NOTE: added MORE EXAMPLE METHODS after class!]
**********

*   references - from "Core Java" text:
    *   Chapter 5 - Section 3 - "generic ArrayLists"
    *   more on Java Collection classes in Chapter 13
    *   more on Java generics in Chapter 12

*   Java Collections classes provide
    MORE collection possibilities in addition to arrays!

    *   also many of these are generics -- they can be
        collections of a specified type;

*   C++ has its STL, Standard Template Library --
    Java has its Collection classes,
    implementations of a number of useful/classic
    data structures;

    *   you can still build your own in Java, but you
        can also use these!

*   these are in package java.util

*   Java added generics relatively recently --
    (their version of C++ templates) --
    you can have a collection type of instances
    whose type YOU specify at declaration type;

    (you put the type in angle brackets after the
    generic type in the declaration -- as we'll soon see)

*   here are SOME of the generic collection classes
    in java.util:

    *   ArrayList - indexed, grows and shrinks dynamically,
                    BUT array-based

    *   LinkedList - an ordered (not necessarily contiguous)
                     linked sequential structure that allows
		     efficient insertions and removals at
       		     any location

    *   HashSet - an unordered collection that rejects
                  duplicates

    *   ArrayDeque - a double-ended queue implemented
                     as a circular array

    *   TreeSet - a sorted set

    *   EnumSet - a set of enumerated type values

    *   HashMap - a data structure that stores key/value
                  associations

    *   PriorityQueue - a collection that allows efficient
                        removal of the smallest element

    *   ETC.

    ...Collection SHOULD be an ancestor Interface for
    all of these; 

    (which means they share many common
    methods!)

*   *********
    IMPORTANT note - these collections are collections
    of objects; cannot have collections of primitive types
    *********

*   Let's play with ArrayList as an example of one
    of these collection classes;

*   it is generic class with a type parameter;

    ******
    NOTE - Java generic classes, like C++ templates,
           actually USE angle brackets AROUND the type
           parameter!

           ...you DO actually type < and > around the
	   specified type after the generic collection name
    *****
    ArrayList<String> names = new ArrayList<String>();

    ArrayList<GameDie> myDieSet = new ArrayList<GameDie>();

*   then, you can add an element to the end of an ArrayList using
    the add method:

    names.add("George");
    myDieSet.add(new GameDie(6));
    myDieSet.add(new GameDie(10));   // now a 10-sided die at end

*   you can get the element at a certain (0-based) position
    using get:

    names.get(0)      // returns "George", given the examples so far
    myDieSet.get(0).roll()   // rolls the 6-sided die at position 0
                             //     in myDieSet
    myDieSet.get(0).getNumRolls()  // would now return 1, given the
                                   //     examples so far

*   you can find out its size -- how many elements it has --
    using the size method:

    names.size()
    myDieSet.size()

*   its 2-argument add method expects a 0-based position and the element
    to be added, and adds it at that position (shifting the current element
    there over) --

    names.add(0, "Alice");

    *   now names contains "Alice" then "George"

*   what if you want to REPLACE an element at a position?
    use set, then:

    names.set(0, "Carol");

    *   now names contains "Carol" then "George"

*   oh, and you can remove an element at a given
    (0-based) position:

    names.add("Tommy");
    names.remove(1);  // removes element at position 1
    
    // now names contains "Carol" then "Tommy"

    ...but you can also remove the FIRST instance of a
    given object, too!

    names.remove("Tommy");

    // now names contains just "Carol"

*   these collection classes often contain additional
    useful methods --

    ArrayList, for example, has
    ensureCapacity(int)

    ...and then it will allocate an array of that
    size, so that many adds WON'T necessitate
    costly relocation;

    can also specify an initial capacity with its
    1-argument constructor:

    ArrayList<Employee> staff = new ArrayList<Employee>(100);

    trimToSize can be used to adjust the memory block
    to JUST what is needed, when the size of an
    ArrayList IS stable (but next add WILL be costly...)

    etc.!

*   and can use the "for each" loop with collections!

    for (String aName: names)
    {
        System.out.println(aName + "!!");
    }

**********
ASIDE after class: Iterator interface
**********

*   a few words about Java iterators

*   Iterator is a generic interface!

    *   provides/requires the methods
    
        E next();
        boolean hasNext();
        void remove();

    *   You call next() repeatedly using the Iterator
        object to "walk" through a collection --

        BUT next() throws an exception if called when
        there ISN'T a next element!

        *   SO, note: you use hasNext() to make SURE there's a next
            element first...

        *   (Yes, Scanner DOES implement the interface
	    Iterator<String>... 8-) )