[prev in list] [next in list] [prev in thread] [next in thread] 

List:       lucene-dev
Subject:    Interfaces
From:       Maik Schreiber <blizzy-keyword-lucene_dev.6564c8 () blizzy ! de>
Date:       2005-03-16 21:32:57
Message-ID: 4238A609.4080404 () blizzy ! de
[Download RAW message or body]

Hi,

I know the issue of using interfaces in Lucene has been discussed a few 
times before. I'd like to bring that to the table once again, though, 
because I think all those discussions were missing an important point: unit 
testing.

Without coding to interfaces it gets quite complicated to test for calls 
being made to an IndexWriter, for example. Of course it's possible to 
subclass IndexWriter and intercept all relevant calls, it still remains 
being a PITA.


Consider the following JUnit test method for testing a hypothetical 
Foo.foo(IndexWriter, Document) method that does nothing more than 
IndexWriter.addDocument(doc):


public void testFoo() throws IOException {
	final List addedDocuments = new ArrayList();

	Directory dir = new RAMDirectory();
	Analyzer analyzer = new StandardAnalyzer();
	IndexWriter writer = new IndexWriter(dir, analyzer, true) {
		public void addDocument(Document doc) throws IOException {
			super.addDocument(doc);
			addedDocuments.add(doc);
		}
	};

	Document doc = new Document();
	new Foo().foo(writer, doc);

	assertEquals(1, addedDocuments.size());
	assertSame(doc, addedDocuments.get(0));
}


As you can see, you have to go at relatively great lengths just to test for 
a single method call. You need to create a Directory for the IndexWriter, 
and the IndexWriter instance itself. The IndexWriter really adds the 
document to the directory. In addition to that, we're taking notes of the 
added documents, so we can assert those later on.

This complexity even grows when doing other this: Say you want to test a 
call to IndexReader. The problem is that IndexReader.open() needs to have a 
valid index lying around. So to set up the environment for that requirement 
you first need to create a fake index in a RAMDirectory using an 
IndexWriter, then use that index to test IndexReader calls.


Now this is the same test method as above, but this time using EasyMock and 
an interface IIndexWriter (which IndexWriter hypothetically implements):


public void testFoo() throws IOException {
	MockControl writerControl =
		MockControl.createControl(IIndexWriter.class);
	IIndexWriter writer = (IIndexWriter) writerControl.getMock();

	Document doc = new Document();

	writer.addDocument(doc);
	writerControl.setVoidCallable();

	writerControl.replay();

	new Foo().foo(writer, doc);

	writerControl.verify();
}


This time, it's all straightforward: No Directory created, no IndexWriter 
created, no document added. We just tell the mocked-up IndexWriter what 
method calls to expect and what to return (or do nothing, or throw an 
exception). Also there's no taking notes of added documents because EasyMock 
does that already.


The net benefit is that there are no useless objects created. Those could 
even harm the test results in the worst case. Also the test should run 
faster now, which can really add up when you have hundreds or thousands of 
tests.

-- 
Maik Schreiber   *   http://www.blizzy.de

GPG public key: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x1F11D713
Key fingerprint: CF19 AFCE 6E3D 5443 9599 18B5 5640 1F11 D713

---------------------------------------------------------------------
To unsubscribe, e-mail: java-dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: java-dev-help@lucene.apache.org

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic