Clean Java Coding and Testing

René Schwietzke, Xceptance

Introduction

The big picture about this lecture.

  • Clean Java programming
  • Java JUnit testing
  • Thinking like a programmer
  • Thinking like a good programmer
  • Thinking like a professional tester

Misc

What you should know before we start.

  • Slides and code are in English only
  • This is not a one-way class
  • Always ask and discuss
  • Some Java knowledge required
  • How to use an IDE is not discussed
  • If we do not make it through, no problem
  • Some stuff could be boring

Programming is like writing books. Not every book is good, not every book will make you famous, not every book will earn you enough.

But a lot of people think they can write a book... cannot be that hard, can it?

License

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

c b a

Feel Good

In 5 minutes

Our First (Test)Code

Couple of lines that show the basics.

  • Code under test and test code in one class.
  • We do not care about the syntax yet.
  • Just copy stuff and make it run.
package org.training.quick;

    import org.junit.Test;
    import static org.junit.Assert.assertEquals;

    public class FeelGood
    {
    	/**
    	 * Returns the max number.
    	 * @param a value one
    	 * @param b value two
    	 * @return the maximum of a and b
    	 */
    	private static int max(final int a, final int b)
    	{
    		if (a < b)
    		{
    			return b;
    		}
    		else
    		{
    			return a;
    		}
    	}

    	@Test
    	public final void test()
    	{
    		assertEquals(3, max (1, 3));
    	}
    }
    

Get a Task

No learning without topic.

Our own ArrayList

Simple data structure with enough functionality but also with enough room for testing and extensions.

  • Similar to java.util.ArrayList
  • No Generics
  • No collection interfaces
  • As plain as possible in the beginning
  • Typed to String

Our Approach

Steps to approach the programming and testing topic.

  • Get the basic idea of an ArrayList
  • Think about the interface
  • Develop an implementation idea
  • Lay the foundation
  • Code it
  • Test it

Requirements and Design

Let the brain do the work first.

What is an ArrayList?

A dynamic array, growable array, resizable array, dynamic table, mutable array, or array list is a random access, variable-size list data structure that allows elements to be added or removed.

  • Dynamic size
  • Random access
  • Adding and Removing
  • List = Index

Basic Functionality

What is the minimal set of functionality that is needed?

  • Does not care about the size
  • Elements can be added but where...
    • Add the end
    • Anywhere
  • Add another ArrayList
  • Get size
  • Remove element but where...
    • Anywhere
    • All at once

Open Questions

Question you should immediately ask yourself.

  • Is null permitted?
  • What happens when something is removed with that position?
  • What happens if I want to remove something that does not exist?
  • How does the dynamic size thing work?
  • Can I insert something beyond the current size?
  • How big can it become?

Check the Environment

Align us to speed up programming.

You need

Verify all of that

  • JDK 8 or higher
  • An IDE, such as Eclipse, Netbeans, or IntelliJ
  • Java skills
  • Motivation

ArrayList Again

Programming our ideas.

Programming

Step-by-step

  • The package
  • The class
  • The basic comments
  • The interfaces
  • Make the skeleton compile
  • Member variables
  • All JavaDoc for methods
  • Code your ideas as comments
  • Finally start to write code

JUnit

Test the hell out of your code!

What is Unit Testing?

How to test code.

  • Examines the behavior of a distinct unit of work.
  • Small, compact, fast, atomic.
  • JUnit is a unit testing framework for the Java programming language.
  • JUnit has been important in the development of test-driven development

Example

	/**
    	 * Removes a string from the list by a given position. If the
    	 * position does not exist, an ArrayIndexOutOfBoundsException is
    	 * thrown.
    	 *
    	 * @param pos the position to remove
    	 * @exception ArrayIndexOutOfBoundsException
    	 * 				when pos is invalid such as negative or too large
    	 * @return the string that has been removed from the list
    	 */
    	public String remove(final int pos)
    	{
    		// get the result
    		final String result = array[pos];

    		// we have to close the hole
    		for (int i = pos; i < size - 1; i++)
    		{
    			array[i] = array[i + 1];
    		}

    		// to be really great to GC, we have to make sure we do not hold
    		// a copy of the last element at the end, this position should be
    		// empty now. Make it so!
    		array[size - 1] = null;

    		// correct size
    		size--;

    		// return the result
    		return result;
    	}
	/**
    	 * Remove last element
    	 */
    	@Test
    	public void removeLastListEntry()
    	{
    		final ArrayList list = new ArrayList();
    		list.add("s1");

    		final String r1 = list.remove(0);

    		Assert.assertEquals(0, list.size());
    		Assert.assertEquals("s1", r1);
    	}

    	/**
    	 * Error handling, remove from empty
    	 */
    	@Test(expected = ArrayIndexOutOfBoundsException.class)
    	public void removeErrorHandling1()
    	{
    		final ArrayList list = new ArrayList();
    		list.remove(0);
    	}

Basic Principles

No strictly enforced.

  • One class under test, one test class.
  • One test case per test method.
  • Each method will run independently.
  • Stateless.
  • Repeatability.
  • Realiability.
  • Predictability.
  • Performance.

Advanced Principles

Everything beyond this class.

  • Hamcrest as matcher.
  • Testing private methods.
  • Mocking connected classes.
  • Mocking system state, e.g. time.
  • Using JUnit as concept not methodology.
  • Spanning into integration testing.
  • Multi-threaded testing.

Mark as Test

@Test

  • Java Annotation
  • Marks a method as test method.
  • Has to be public.
  • No return value, no exception permitted.
/**
     * Remove last element
     */
    @Test
    public void removeLastListEntry()
    {
    	final ArrayList list = new ArrayList();
    	list.add("s1");

    	final String r1 = list.remove(0);

    	Assert.assertEquals(0, list.size());
    	Assert.assertEquals("s1", r1);
    }

Assert an assumption

org.junit.Assert

  • Verify the state.
  • Proves the expectations.
  • Can be used often.
  • No very luxurious.
  • For later: http://hamcrest.org/JavaHamcrest/.
/**
     * Test adding the same data again
     */
    @Test
    public void addHandlingDuplicateData()
    {
    	final String A = "foo1";
    	final String B = new String("foo1");

    	// this is the string challenge :)
    	Assert.assertNotSame(A, B);
    	Assert.assertEquals(A, B);

    	final ArrayList list = new ArrayList();
    	Assert.assertEquals(0, list.size());
    }

Expect something

@Test (expect = Exception.class)

  • Check that the exception is thrown.
  • Provoke it.
  • Only type not text can be verified.
/**
     * Test error handling
     */
    @Test(expected=NullPointerException.class)
    public void addErrorHandling()
    {
    	final ArrayList list = new ArrayList();
    	list.add((String)null);
    }

Setup

@After, @Before...

  • Create data needed.
  • Once per class or once per method.
  • Make sure the cleanup is safe!
  • Do not create side-effects.
/**
     * Setup data for the test once
     */
    @BeforeClass
    public void createSomethingOnce() {}

    /**
    * Setup data for the test before each method
    */
    @Before
    public void createSomething() {}

    /**
    * Clean up after each test
    */
    @After
    public void removeStuff() {}

    /**
    * Clean up stuff once
    */
    @After
    public void removeStuffOnce() {}
    

Coverage

Measure your testing.

  • Use tools to measure your test reach.
  • See that you touched every line.
  • See that you covered every branch.
  • Does not mean, the test is meaningful.