270 likes | 436 Views
Mocking Your Objects with Impunity. Goal of Presentation. Show how “Mocking Objects” can greatly improve unit testing by facilitating tests that are easier to write and less dependant upon objects outside the test domain. Topics of Discussion. What is Object Mocking? Why Mock Objects?
E N D
Mocking Your Objects with Impunity Presented by Ernest Hill ernesthill@earthlink.net
Goal of Presentation • Show how “Mocking Objects” can greatly improve unit testing by facilitating tests that are easier to write and less dependant upon objects outside the test domain Presented by Ernest Hill ernesthill@earthlink.net
Topics of Discussion • What is Object Mocking? • Why Mock Objects? • What tools are available to support Object Mockery Presented by Ernest Hill ernesthill@earthlink.net
What is Object Mocking? • Creating a mock implementation of an object that can be used as a stand-in in testing • A mock objects allow you to set expectations • The mock object lets you verify that the expectations were met Presented by Ernest Hill ernesthill@earthlink.net
Why engage in Object Mocking? • The real object has behaviour that is hard to cause or is non-deterministic • The real object is difficult to set up • The real object is slow • The real object has (or is ) a UI • Test needs to query the object but queries are not available • Real objects do not exist Presented by Ernest Hill ernesthill@earthlink.net
What tools are available to support Obect Mockery • The MockObjects framework • MockMaker • EasyMockt Presented by Ernest Hill ernesthill@earthlink.net
MockObjects Framework • Open source framework available at MockObjects.org • Provides some utility tools for creating mock objects • Provides mock implementations of common libraries such as IO, Servlets and JDBC Presented by Ernest Hill ernesthill@earthlink.net
MockMaker Overview • Open source tool available at mockmaker.org • Passive code generation tool • Generates mock objects that depend on the MockObjects framework • Has a command line and gui interface • Mock objects can only be generated from an interface Presented by Ernest Hill ernesthill@earthlink.net
MockMaker Features • Generated MockObject has • Methods to set expected minimal method call • Methods to set expected parameter values • Methods to set return value from method • Method to verify everything was as expected Presented by Ernest Hill ernesthill@earthlink.net
MockMaker Drawbacks • Interface being used is not directly visible • If interface changes MockObject must be modified or regenerated • No method to throw exceptions Presented by Ernest Hill ernesthill@earthlink.net
EasyMock Overview • Open source tool available at easymock.org • Uses reflection to dynamically create proxies that implement the interface at run time • EasyMock generates two objects the EasyMock Mock Object and the EasyMock Mock Control Presented by Ernest Hill ernesthill@earthlink.net
EasyMock Features • Allows the expected parameter value to be set for each method • Allows you to set up the value to be returned by each method • Allows the number of times the method is to be invoked to be specified • Allows you to specify an exception the a method should throw • Will verify that everything went as expected Presented by Ernest Hill ernesthill@earthlink.net
EasyMock Drawbacks • EasyMock generates objects on the fly so you can’t add any behaviour • EasyMock uses the equals method to compare parameters Presented by Ernest Hill ernesthill@earthlink.net
Test Domain • We need to test a Copier class • The Copier constructor takes a Reader and a Writer • The Copier copy method reads from the Reader and Writes to the Writer until the Reader returns null Presented by Ernest Hill ernesthill@earthlink.net
public interface Reader { public String readln(); } public interface Writer { public void writeln(String line); } Interfaces Presented by Ernest Hill ernesthill@earthlink.net
Copier • public class Copier { • private Reader reader; • private Writer writer; • public Copier(Reader aReader, Writer aWriter) { • this.reader = aReader; • this.writer = aWriter; • } • public void copy() { • String line; • while ( ( line = reader.readln() ) != null ) • writer.writeln(line); • } • } Presented by Ernest Hill ernesthill@earthlink.net
Run MockMaker • java mockmaker.MockMaker Reader > MockReader.java • java mockmaker.MockMaker Writer > MockWriter.java Presented by Ernest Hill ernesthill@earthlink.net
MockReader.java • import mockmaker.ReturnValues; • import com.mockobjects.*; • import Reader; • public class MockReader implements Reader{ • private ExpectationCounter myReadlnCalls = new ExpectationCounter("Reader ReadlnCalls"); • private ReturnValues myActualReadlnReturnValues = new ReturnValues(false); • public void setExpectedReadlnCalls(int calls){ • myReadlnCalls.setExpected(calls); • } • public String readln(){ • myReadlnCalls.inc(); • Object nextReturnValue = myActualReadlnReturnValues.getNext(); • return (String) nextReturnValue; • } • public void setupReadln(String arg){ • myActualReadlnReturnValues.add(arg); • } • public void verify(){ • myReadlnCalls.verify(); • } • } Presented by Ernest Hill ernesthill@earthlink.net
MockWriter.java • import mockmaker.ReturnValues; • import com.mockobjects.*; • import Writer; • public class MockWriter implements Writer{ • private ExpectationCounter myWritelnCalls = new ExpectationCounter("Writer WritelnCalls"); • private ExpectationList myWritelnParameter0Values = new ExpectationList("Writer WritelnParameter0Values"); • public void setExpectedWritelnCalls(int calls){ • myWritelnCalls.setExpected(calls); • } • public void addExpectedWritelnValues(String arg0){ • myWritelnParameter0Values.addExpected(arg0); • } • public void writeln(String arg0){ • myWritelnCalls.inc(); • myWritelnParameter0Values.addActual(arg0); • } • public void verify(){ • myWritelnCalls.verify(); • myWritelnParameter0Values.verify(); • } • } Presented by Ernest Hill ernesthill@earthlink.net
Unit test using MockMaker • public void testCopy() { • MockReader mockReader = new MockReader(); • mockReader.setupReadln("ABC"); • mockReader.setupReadln(null); • mockReader.setExpectedReadlnCalls(2); • MockWriter mockWriter = new MockWriter(); • mockWriter.addExpectedWritelnValues("DEF"); • mockWriter.setExpectedWritelnCalls(1); • Copier copier = new Copier(mockReader, mockWriter); • copier.copy(); • mockReader.verify(); • mockWriter.verify(); • } Presented by Ernest Hill ernesthill@earthlink.net
Unit test results • =================================================== • Errors logged for the 'CopierTest' test: • No errors. • =================================================== • Failures logged for the 'CopierTest' test: • Total failures: 1 • Test case 'testCopy(CopierTest)' failed with 'Writer WritelnParameter0Values Writer WritelnParameter0Values added item does not match • Expected: DEF • Received: ABC' • at CopierTest.testCopy(CopierTest.java:40) • =================================================== • Summary of 'CopierTest' test: • Result: Failed • Run: 1 • Failures: 1 • Errors: 0 • Elapsed time: 0.07 Presented by Ernest Hill ernesthill@earthlink.net
Unit Test with EasyMock • public void testCopy(){ • MockControl mockReaderControl = EasyMock.controlFor(Reader.class); • Reader mockReader = (Reader) mockReaderControl.getMock(); • mockReader.readln(); • mockReaderControl.setReturnValue("ABC", 1); • mockReaderControl.setReturnValue(null, 1); • mockReaderControl.activate(); • MockControl mockWriterControl = EasyMock.controlFor(Writer.class); • Writer mockWriter = (Writer) mockWriterControl.getMock(); • mockWriter.writeln("DEF"); • mockWriterControl.setVoidCallable(1); • mockWriterControl.activate(); • Copier copier = new Copier(mockReader, mockWriter); • copier.copy(); • mockReaderControl.verify(); • mockWriterControl.verify(); • } Presented by Ernest Hill ernesthill@earthlink.net
Results of Unit Test with Easy Mock • =================================================== • Errors logged for the 'CopierTest' test: • No errors. • =================================================== • Failures logged for the 'CopierTest' test: • Total failures: 1 • Test case 'testCopy(CopierTest)' failed with 'EasyMock for interface Writer: • Unexpected method call writeln("ABC")' • at CopierTest.testCopy(CopierTest.java:60) • =================================================== • Summary of 'CopierTest' test: • Result: Failed • Run: 1 • Failures: 1 • Errors: 0 • Elapsed time: 0.181 Presented by Ernest Hill ernesthill@earthlink.net
Throwing an exception • public void testCopy() { • MockControl mockReaderControl = EasyMock.controlFor(Reader.class); • Reader mockReader = (Reader) mockReaderControl.getMock(); • mockReader.readln(); • mockReaderControl.setThrowable(new Error("Test Exception"), 1); • mockReaderControl.activate(); • MockControl mockWriterControl = EasyMock.controlFor(Writer.class); • Writer mockWriter = (Writer) mockWriterControl.getMock(); • mockWriter.writeln("DEF"); • mockWriterControl.setVoidCallable(1); • mockWriterControl.activate(); • Copier copier = new Copier(mockReader, mockWriter); • try { • copier.copy(); • fail("copier.copy() should have thrown an exception"); • } catch ( Error err ) { • assertEquals("err.getMessage() returned wrong text", "Test Exception", err.getMessage()); • } • mockReaderControl.verify(); • mockWriterControl.verify(); • } Presented by Ernest Hill ernesthill@earthlink.net
Results of Unit Test with Exception • =================================================== • Errors logged for the 'CopierTest' test: • No errors. • =================================================== • Failures logged for the 'CopierTest' test: • Total failures: 1 • Test case 'testCopy(CopierTest)' failed with 'EasyMock for interface Writer: Expectation failure on verify: • method call writeln("DEF"): calls expected: 1, received: 0' • at CopierTest.testCopy(CopierTest.java:87) • =================================================== • Summary of 'CopierTest' test: • Result: Failed • Run: 1 • Failures: 1 • Errors: 0 • Elapsed time: 0.17 Presented by Ernest Hill ernesthill@earthlink.net
What this means • Object Mocking is an invaluable technique for improving the overall quality of your unit tests. Presented by Ernest Hill ernesthill@earthlink.net
Resources • www.mockobjects.com • www.mockmaker.org • www.easymock.com • EasyMock: Dynamic Mock Objects for JUnit see www.xp2002.org/atti/TammoFreese--EasyMock.pdf • Automatically Generating System Mock Objects -http://www.xpuniverse.com/2001/pdfs/Testing04.pdf • Test flexibly with AspectJ and mock objects –www-106.ibm.com/developerworks/java/library/j-aspectj2/?open&l=007,t=gr • MockDoclet – http://joe.truemesh.com/mockdoclet Presented by Ernest Hill ernesthill@earthlink.net