Mastering Mock Objects - Advanced Unit Testing for Java


Published on

A high-level description of mock testing techniques and their implementation for the Java programming language.

This presentation specifically focus on the JMockit and JMock frameworks.

Published in: Technology, Education
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Mastering Mock Objects - Advanced Unit Testing for Java

  1. 1. Advanced Unit Testing for Java By Denilson Nastacio Mastering Mock Objects
  2. 2. Your Host <ul><li>Denilson Nastacio </li></ul><ul><li>14 years in software development </li></ul><ul><li>Quality Enthusiast </li></ul><ul><li>Rational Unified Process practitioner </li></ul><ul><li>RTP Scrolls ( ) </li></ul><ul><li>SourcePatch ( ) </li></ul><ul><li>LinkedIn ( ) </li></ul>
  3. 3. Agenda <ul><li>Concepts </li></ul><ul><li>Intercepting methods </li></ul><ul><li>Declaring expectations </li></ul><ul><li>Tools </li></ul>
  4. 4. Different levels of abstraction <ul><li>Code logic </li></ul><ul><ul><li>Tests whether isolated methods respect their exposed contract </li></ul></ul><ul><ul><li>Guarantees that there are no broken code paths </li></ul></ul><ul><ul><li>No runtime dependencies: mock objects </li></ul></ul><ul><li>Integration test (by developer, not QA organization) </li></ul><ul><ul><li>Tests combination of classes and runtime environment </li></ul></ul><ul><ul><li>Require runtime support </li></ul></ul><ul><ul><li>Detect incompatibilities between components </li></ul></ul><ul><ul><li>Residual code logic tests </li></ul></ul><ul><li>Function test (by developer, not QA organization) </li></ul><ul><ul><li>Real end-user scenarios </li></ul></ul><ul><ul><li>Residual code logic and integration test. </li></ul></ul>A C E D B A C E B A C E D B
  5. 5. Ideal resource allocation Code logic Integration Function QA Function Test Development Dev QA System Test Runtime dependencies Cost per volume of code
  6. 6. The case against system dependencies on unit testing <ul><li>Complex </li></ul><ul><ul><ul><li>Create user accounts, upgrade OS, install fixpacks, etc </li></ul></ul></ul><ul><li>Slow </li></ul><ul><ul><ul><li>Minutes to recycle servers between tests </li></ul></ul></ul><ul><li>Unnecessary </li></ul><ul><ul><ul><li>During development, you want to test the code, purge logic errors before starting test integration </li></ul></ul></ul>
  7. 7. Code logic test <ul><li>Classes tested in isolation </li></ul><ul><li>Black box testing </li></ul><ul><ul><ul><li>Based on declared interfaces, not actual implementation </li></ul></ul></ul><ul><ul><ul><li>Guarantees that methods respect their declared interfaces </li></ul></ul></ul><ul><ul><ul><li>Good to validate public APIs </li></ul></ul></ul><ul><ul><ul><li>Bad for validating exceptions related to environment problems </li></ul></ul></ul><ul><ul><li>White box testing </li></ul></ul><ul><ul><ul><li>Based on implementation, usually due to incomplete specifications </li></ul></ul></ul><ul><ul><ul><li>Typical of test written after the fact </li></ul></ul></ul><ul><ul><ul><li>Concerned with exhaustive test of all lines in the actual source code </li></ul></ul></ul><ul><ul><ul><li>Good to verify exception handling when combined with mock objects </li></ul></ul></ul>
  8. 8. Mock environments for Java
  9. 9. Classes of mock environments <ul><li>Environment simulators </li></ul><ul><ul><li>Respond like the real environment </li></ul></ul><ul><ul><li>Pros: Simulate complex behavior without environment dependencies </li></ul></ul><ul><ul><li>Cons: Few simulators available, maintaining a simulator rivals the complexity of maintaining a real application </li></ul></ul><ul><li>Mock object frameworks </li></ul><ul><ul><li>Same interfaces as the real environment </li></ul></ul><ul><ul><li>Developer must preset the mock objects with the expected responses </li></ul></ul><ul><ul><li>Pros: Mock objects can be generated quickly for any environment </li></ul></ul><ul><ul><li>Cons: Presetting mock objects for unit tests may require lots of code </li></ul></ul>
  10. 10. Mock libraries <ul><li>JMockit </li></ul><ul><ul><li>Instructs the JVM to replace calls to any method with code under your control </li></ul></ul><ul><ul><li>One-two punch with JMock against bunkered initialization within the production code, such as calls to constructors or static methods </li></ul></ul><ul><ul><li>Use JMockit to intercept calls to static methods deep into the production code and return JMock pre-programmed objects. </li></ul></ul><ul><ul><li> </li></ul></ul><ul><li>JMock </li></ul><ul><ul><li>Pre-program objects to expect calls and return values of your choice </li></ul></ul><ul><ul><li>Instruct the production code to “talk to” mocked object instead of actual system dependency </li></ul></ul><ul><ul><li>Mocks interfaces and classes. </li></ul></ul><ul><ul><li> </li></ul></ul>
  11. 11. Anatomy of JMock in a test fixture <ul><li>@Test </li></ul><ul><li>public void testTransferFunds() throws Exception { </li></ul><ul><li>org.jmock.Mockery context = new Mockery(); </li></ul><ul><li>context.setImposteriser(ClassImposteriser. INSTANCE ); </li></ul><ul><li>final float testAmount = 300; </li></ul><ul><li>final BankAccount sourceAccount = context.mock(BankAccount. class , &quot;source&quot; ); </li></ul><ul><li>final BankAccount targetAccount = context.mock(BankAccount. class , &quot;target&quot; ); </li></ul><ul><li>org.jmock.Expectations expect = new Expectations() { </li></ul><ul><li>{ </li></ul><ul><li>one(sourceAccount).withdraw(testAmount); </li></ul><ul><li>one(targetAccount).deposit(testAmount); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>context.checking(expect); </li></ul><ul><li>Transaction tx = new Transaction(); </li></ul><ul><li>tx.transferFunds(testAmount, sourceAccount, targetAccount); </li></ul><ul><li>context.assertIsSatisfied(); </li></ul><ul><li>} </li></ul>Create mock Context Create mock instances Programs mock instances Adds expectation to mock context. Asks context whether all expectations were met.
  12. 12. Anatomy of JMockit in a test fixture – Inlined mock <ul><li>@Mocked private final BankSOAUtil unused = null ; </li></ul><ul><li>@Test </li></ul><ul><li>public void testBankAccountSOA() throws Exception { </li></ul><ul><li>String inputDir = &quot;abc&quot; ; </li></ul><ul><li>final String inputFile = &quot;AndrewBankAccountData.xml&quot; ; </li></ul><ul><li>new mockit.Expectations() { </li></ul><ul><li>{ </li></ul><ul><li>BankSOAUtil. getInputStream ((URL)withNotNull()); </li></ul><ul><li>returns( new FileInputStream(inputFile)); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>// Bank account constructor reads its configuration using </li></ul><ul><li>// BankSOAUtil.getInputStream </li></ul><ul><li>BankAccount bc = new BankAccount( &quot;userid&quot; , &quot;password&quot; ); </li></ul><ul><li>Assert. assertEquals ( &quot;Andrew&quot; , bc.getCustomerName()); </li></ul><ul><li>} </li></ul>Inlined mocked expectation Programming the expectation Marking class to be mocked
  13. 13. Anatomy of JMockit in a test fixture – Using a mock class <ul><li>public void testBankAccountSOA() throws Exception {s </li></ul><ul><li>Mockit.setUpMocks(MockBankSOAUtil.class); </li></ul><ul><li>String inputFile = &quot;AndrewBankAccountData.xml&quot;; </li></ul><ul><li>// Bank account constructor reads its configuration using </li></ul><ul><li>// BankSOAUtil. getInputStream </li></ul><ul><li>BankAccount bc = new BankAccount(...); </li></ul><ul><li>Assert.assertEquals(&quot;Andrew&quot;, bc.getCustomerName()); </li></ul><ul><li>Mockit.tearDownMocks(); </li></ul><ul><li>} </li></ul><ul><li>@MockClass(realClass = BankSOAUtil.class) </li></ul><ul><li>public static class MockBankSOAUtil { </li></ul><ul><li>private static String inputFile = null; </li></ul><ul><li>@Mock(invocations = 1) </li></ul><ul><li>public static InputStream getInputStream (URL inputUrl) </li></ul><ul><li>throws IOException { </li></ul><ul><li>return new FileInputStream(inputFile) ; </li></ul><ul><li>} </li></ul><ul><li>public static void setInputFile(String inputFile) { </li></ul><ul><li>MockDogearUtil.inputFile = inputFile ; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>Instructs the JVM about the mock classes to be used Instructs the JVM to stop using JMockit mocks. Declares the production class to be mocked Indicates which methods of the production class should be mocked
  14. 14. Which one should I use? <ul><li>JMockit </li></ul><ul><ul><ul><li>Can intercept any call to the JVM </li></ul></ul></ul><ul><ul><ul><li>Added many improvements to expectation support during 2009 </li></ul></ul></ul><ul><ul><ul><li>Supports bytecode level coverage metrics </li></ul></ul></ul><ul><ul><ul><li>My new favorite </li></ul></ul></ul><ul><li>JMock </li></ul><ul><ul><ul><li>Used to have better control over behavior of mocked object </li></ul></ul></ul><ul><ul><ul><li>My former favorite </li></ul></ul></ul><ul><ul><ul><li>Needs production code to provide “entry points” to receive the mocked objects </li></ul></ul></ul>
  15. 15. Building mock expectations <ul><li>Required versus allowed </li></ul><ul><ul><li>Is it important that the mocked method be actually called? </li></ul></ul><ul><ul><li>JMock: allowing/ignored/one </li></ul></ul><ul><ul><li>JMockit: Expectations, Verifications, and sub-classes </li></ul></ul><ul><li>Specific versus loose </li></ul><ul><ul><li>Is it important that the mocked method be actually called with a specific parameter? </li></ul></ul><ul><ul><li>Both JMock and JMockit offer out-of-the-box matchers for concepts like 'same value', 'same class', 'inherited from a class', 'null', 'not null', and others </li></ul></ul>
  16. 16. When results matter – 1 of 3 <ul><li>What if results from a dependency matter? </li></ul><ul><ul><li>public class ExternalClass { </li></ul></ul><ul><ul><li>public String somethingWithAReturnValue(String input) { </li></ul></ul><ul><ul><li>return &quot;DEF&quot; ; </li></ul></ul><ul><ul><li>} </li></ul></ul>
  17. 17. When results matter – JMock 2 of 3 <ul><li>final ExternalClass ecMock = context.mock(ExternalClass. class ); </li></ul><ul><li>org.jmock.Expectations expect = new org.jmock.Expectations() { </li></ul><ul><li>{ </li></ul><ul><li>one(ecMock).somethingWithAReturnValue( &quot;specific value&quot; ); </li></ul><ul><li>will( returnValue ( &quot;someReturnValue&quot; )); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>final ExternalClass ecMock = context.mock(ExternalClass. class ); </li></ul><ul><li>org.jmock.Expectations expect = new org.jmock.Expectations() { </li></ul><ul><li>{ </li></ul><ul><li>one(ecMock).somethingWithAReturnValue(with( any (String. class ))); </li></ul><ul><li>will( returnValue ( &quot;someReturnValue&quot; )); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>Use with(any(Class <T> type)) to instruct the JMock mock to ignore input parameters
  18. 18. When results matter – Jmockit - 3 of 3 <ul><li>new mockit.Expectations () { </li></ul><ul><li>ExternalClass EcMock; </li></ul><ul><li>{ </li></ul><ul><li>ecMock.somethingWithAReturnValue( &quot;specific value&quot; ); </li></ul><ul><li>returns( &quot;someReturnValue&quot; )); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>new mockit.Expectations () { </li></ul><ul><li>ExternalClass EcMock; </li></ul><ul><li>{ </li></ul><ul><li>ecMock.somethingWithAReturnValue(withAny( &quot;&quot; ); </li></ul><ul><li>returns( &quot;someReturnValue&quot; )); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>Use withAny(Class <T> type)) to instruct the JMockit mock to ignore input parameters
  19. 19. Great companion tools <ul><li>DDTUnit </li></ul><ul><ul><li> </li></ul></ul><ul><li>Cobertura </li></ul><ul><ul><li> </li></ul></ul><ul><ul><li>Note: JMockit has its own code coverage support </li></ul></ul>