Erik, > It appears you are wrapping Lucene. So, if you truly want to mock > things for testing purposes, come up with a generic interface > (SearchManager?!) that has the search method signature that you have > above and all the other pieces you're wrapping. Then create a mock > implementation of that particular interface.
Setting up an interface as you suggest is what I did, and I create mock impls of that as I need in other test cases. But I also want to unit test the _implementation_ itself? Here is the full code of the implementation: package org.componenthaus.search; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.Searcher; import java.io.File; import java.io.IOException; import java.util.List; public class LuceneSearchService implements SearchService { private static final String INDEX_FILE_PATH = "index"; //This is impossible to unit test as IndexWriter is final public void index(String componentId, String componentDescription) throws SearchService.Exception { IndexWriter writer = null; try { writer = new IndexWriter(INDEX_FILE_PATH, new StandardAnalyzer(), !indexExists()); final Document document = new Document(); document.add(Field.Text("id", componentId)); document.add(Field.Text("contents", componentDescription)); writer.addDocument(document); writer.optimize(); writer.close(); } catch (IOException e) { throw new SearchService.Exception("Exception updating Lucene index", e); } } private boolean indexExists() { return new File(INDEX_FILE_PATH).exists(); } //This is impossible to unit test as Hits is final, and the constructor is package protected public int search(final String query, int beginIndex, final int endIndex, final List collector) throws SearchService.Exception { int numHits = 0; try { final Searcher searcher = new IndexSearcher(INDEX_FILE_PATH); final Analyzer analyzer = new StandardAnalyzer(); final Query q = QueryParser.parse(query, "contents", analyzer); final Hits hits = searcher.search(q); numHits = hits.length(); while (beginIndex <= endIndex && beginIndex < numHits) { final Document doc = hits.doc(beginIndex++); collector.add(doc.get("id")); } } catch (java.lang.Exception e) { throw new SearchService.Exception("Exception performing Lucene search",e); } return numHits; } } You are right that this code as it currently stands cannot be unit tested using mock-objects. Thats because I tried to do so, ran into the final problem, then rolled back. I will show you roughly how the code looked when I refactored it to be mock-ready: public class LuceneSearchService implements SearchService { private static final String INDEX_FILE_PATH = "index"; private Context context = new DefaultContext(); public void setContext(Context c) { this.context = c; } public void index(String componentId, String componentDescription) throws SearchService.Exception { IndexWriter writer = null; try { writer = context.createIndexWriter(INDEX_FILE_PATH, new StandardAnalyzer(), !indexExists()); final Document document = new Document(); document.add(Field.Text("id", componentId)); document.add(Field.Text("contents", componentDescription)); writer.addDocument(document); writer.optimize(); writer.close(); } catch (IOException e) { throw new SearchService.Exception("Exception updating Lucene index", e); } } public static interface Context { IndexWriter createIndexWriter(String path, Analyzer a, boolean create); } private static final class DefaultContext { IndexWriter createIndexWriter(String path, Analyzer a, boolean create) { return new IndexWriter(path, a, create); } } Now my test case becomes: public void testCase() { MockContext context = new MockContext(); MockIndexWriter indexWriter = new IndexWriter(); context.setupExpectedIndexWriter(indexWriter); indexWriter.setupExpectedCloseCalls(1); indexWriter.setupIOException(true); LuceneSearchService service = new LuceneSearchService(); service.setContext(context); //Should throw IOException as instructed to do above service.index(componentId, componentDescription); //But we should still have a closed indexWriter. context.verify(); } public class MockContext implements LuceneSearchService.Context { IndexWriter createIndexWriter(String path, Analyzer a, boolean create) { return new MockIndexWriter(path, a, create); } } I don't know if you see any value in that, but I do. I cannot do it because IndexWriter is final and I cannot create a MockIndexWriter. I can do a RAMDirectory and use the real Lucene API, but I find that less convenient than the above. Do you not agree? Cheers, Mike. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]