CodeUnitTestFirstExampleTwo

Last edit May 21, 2007
Example of how to CodeUnitTestFirst:

(see UnitTestExamplesAndGuidelines)
Suppose that I want to write a class to get a not yet existing file. I'd start with a simple test:
 public class FileGetterTest{
	private FileGetter fileGetter;
	private File file;
	//
	public void testGetFile(){
		fileGetter = new FileGetter();
		file = fileGetter.getFile();
		assertTrue(file != null);
	}
 }
The simplest possible small bit of functionality... give me a file, any file will do. Now, write a stub implementation:
 public class FileGetter{
	public File getFile(){
		return null;
	}
 }
And run the test. It fails. Excellent. Why, you ask? This proves that the test works, or at least that it doesn't give a false negative. Okay, fill in the implementation.
 public class FileGetter{
	public File getFile(){
		return new File();
	}
 }
And run the test. Okay, it passes, but it's still not really useful... okay, write another small test.
 public class FileGetterTest{
	private FileGetter fileGetter;
	private File file;
	//
	public void testGetFile(){
		fileGetter = new FileGetter();
		file = fileGetter.getFile();
		assertTrue(file != null);
		assertTrue(!file.isDirectory());
	}
 }
And run the test. It fails...
 public class FileGetter{
	public File getFile(){
		return new File("somenicefilename.txt");
	}
 }
And it passes, and is kindof useful, it indeed gets a valid file... but is it unique? Well, let's find out
 public class FileGetterTest{
	private FileGetter fileGetter;
	//
	public void testGetFile(){
		fileGetter = new FileGetter();
		File file = fileGetter.getFile();
		assertTrue(file != null);
		assertTrue(!file.isDirectory());
		//
		File anotherFile = fileGetter.getFile();
		assertTrue(!file.equals(anotherFile));
	}
 }
And it fails (seeing a pattern here?) Hmm... is this really what we want? What happens if somebody requests a file, but never uses it? Oops, nevermind... DoTheSimplestThingThatCouldPossiblyWork: so what if they never use it. We're only worrying about getting a unique file at this point. Okay, the implementation, now starting to get useful:
 public class FileGetter{
	private int index = 0;
	//
	public File getFile(){
		index++;
		return new File("somenicefilename" + index + ".txt");
	}
 }
Okay, tests passed. Next, we'll we still haven't checked if the file already exists or not... on with the test:
 public class FileGetterTest{
	private FileGetter fileGetter;
	//
	public void testGetFile(){
		fileGetter = new FileGetter();
		File file = fileGetter.getFile();
		assertTrue(file != null);
		assertTrue(!file.isDirectory());
		//
		File anotherFile = fileGetter.getFile();
		assertTrue(!file.equals(anotherFile));
	}
	//
	public void testGetExistingFile(){
		fileGetter = new FileGetter();
		File testFile = fileGetter.getFile();
		//
		fileGetter = new FileGetter();	
		testFile.createNewFile();
		assertTrue(!testFile.equals( fileGetter.getFile() ));		
	}
 }
And... it fails.
 public class FileGetter{
	private int index = 0;
	//
	public File getFile(){
		File nextFile;
		do{
			nextFile = getNextFile();
		}while(nextFile.exists());
		return nextFile;
	}
	//
	public File getNextFile(){
		index++;
		return new File("somenicefilename" + index + ".txt");
	}
 }
And, the tests pass, it pretty much does what it's supposed to do, anything else that should be tested? Well, we're assuming that a every FileGetter instance will always return the same non existing file, so we should put in a test to let us know if that assumption ever becomes wrong. Any other assumptions discovered should be guarded in the same way.
 public class FileGetterTest{
	private FileGetter fileGetter;
	//
	public void testGetFile(){
		fileGetter = new FileGetter();
		File file = fileGetter.getFile();
		assertTrue(file != null);
		assertTrue(!file.isDirectory());
		//
		File anotherFile = fileGetter.getFile();
		assertTrue(!file.equals(anotherFile));
	}
	//	
	public void testGetExistingFile(){
		fileGetter = new FileGetter();
		File testFile = fileGetter.getFile();
		//
		fileGetter = new FileGetter();	
		testFile.createNewFile();
		assertTrue(!testFile.equals( fileGetter.getFile() ));		
	}
	//
	public void testDeterministicBehaviour(){
		fileGetter = new FileGetter();
		File testFile = fileGetter.getFile();
		//		
		fileGetter = new FileGetter();
		assertEquals(testFile, fileGetter.getFile());
	}
 }
Tests pass, okay! Any refactoring? Well, parts of each test should be refactored into a setup method, and the 'somenicefilename' bit could probably be dumped... we really don't need it according to the simple story above. So, we end up with something like this:
 public class FileGetterTest{
	private FileGetter fileGetter;
	private File testFile;
	//
	protected void setUp(){
		super.setUp();
		fileGetter = new FileGetter();
		testFile = fileGetter.getFile();	
	}
	//
	public void testGetFile(){
		assertTrue(testFile != null);
		assertTrue(!testFile.isDirectory());
		//
		File anotherFile = fileGetter.getFile();
		assertTrue(!testFile.equals(anotherFile));
	}
	//	
	public void testGetExistingFile(){
		fileGetter = new FileGetter();
		testFile.createNewFile();
		assertTrue(!testFile.equals( fileGetter.getFile() ));		
	}
	//
	public void testDeterministicBehaviour(){
		fileGetter = new FileGetter();
		assertEquals(testFile, fileGetter.getFile());
	}
 }

public class FileGetter{ private int index = 0; private File nextFile; // public File getFile(){ do{ setNextFile() }while(nextFile.exists()); return nextFile; } // public void setNextFile(){ index++; nextFile = new File(index + ".tmp"); } }
And we're left with a class which does exactly what we want it to, and a set of tests which will tell us if anything happens to change that.