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.