Sunday, May 27, 2012

JMockit Tutorial: How does JMockit support mocking?

JMockit is a java framework for mocking objects in JUnit testing. It uses the instrumentation apis that modify the bytecode during run time to dynamically create classes. The API model can be seen here.

The following are short descriptions about the most used tools offered by JMockit:
  1. JMockit Expectations: This class is the most used for a mocking the results of a  method by specifying what is expected when a particular method is invoked. JMockit names the setting of expectations as record phase and when the actual call to the method happens, its called the replay phase. Thus the jargon record-replay model. The object/class whose method is going to be mocked should be annotated using the @Mocked annotation in the class scope or should be  declared locally  in the expectations block.
    The following example will make all the mumbo jumbo above clear.
    /************* "Person.java" *********/
    public class Person {
    
     String name = "Abhi" ;
    
     public String getName() {
      return name;
     }
    
     public void setName(String name) {
      this.name = name;
     }
    
    }
    /************* "Department.java" *********/
    public class Department{
     Person person = new Person();//Person is the 'collaborator'- a fancy name for third party object
     
     public String getPersonName(){
      return person.getName();
     }
    }
    
    /************* "DepartmentTest.java" *********/
    public class DepartmentTest{
     @Mocked
     Person person;//The mocked object.Note that I am NOT using new to create an instance.
     
    
     @Test
     public void testGetName(){
      Department  dept = new Department();
      new Expectations(){
       //locally defined objects are automatically considered mocked
       {
        person.getName();//Setting the expected behaviour here. 
        returns("Nandan");//Will return Nandan instead of Abhi
       }
      };
      
      String name = dept.getPersonName();
      assertEquals("Name Should be Nandan","Nandan",name);
      
     }
    }
    

    The code is pretty self explanatory, I am mocking the getName() method to return "Nandan" which may take up various forms when you are writing the unit tests.
    Before we jump onto Verifications, Expectations block is a strict checking mechanism-the test run will fail if 
    • The calls in the expectation block are not replayed.
    • There is more than one call of the same method
    • There is a call for another method
    All this can be overcome by using the NonStrictExpectation class.Go through this link for an in depth understanding of the Expectations class.
  2. JMockit Verifications:  As the name suggests this class is used to *verify* something after a test method call has taken place. Extending the record-replay model, it becomes record-replay-verify model. Verifications can be used to explicitly check if a call has been made and how many times.Now onto the code....
    /************* "Person.java" *********/
    public class Person {
    
     String name = "Abhi" ;
    
     public String getName() {
      return name;
     }
    
     public void setName(String name) {
      this.name = name;
     }
    
    }
    /************* "Department.java" *********/
    public class Department{
     Person person = new Person();//Person is the 'collaborator'- a fancy name for third party object
     
     public String getPersonName(){
      return person.getName();
     }
    }
    
    /************* "DepartmentTest.java" *********/
    public class DepartmentTest{
     @Mocked
     Person person;//The mocked object.Note that I am NOT using new to create an instance.
     
    
     @Test
     public void testGetNameCalls(){
      Department dept  = new Department();
      String name = dept.getPersonName();
      new Verifications(){
       {
        person.getName();//verify that this method is called when dept.getPersonName() is invoked
       }
      };
     }
    }
    
    We can also specify the constraints for the number of times a method has to be called. Go through this link to understand how times,minTimes, and maxTimes fields can be used.
  3. JMockit Inline MockUps : This is my personal favourite. And I would say its the most powerful feature of JMockit to redefine methods/static blocks/constructors. I will be posting how to do all of that in the coming blogs. As of now, we'll see how to create a inline mockup that redefines a method for our test case.See the JMockit documention of MockUp for more information.
    /************* "Person.java" *********/
    public class Person {
    
     String name = "Abhi" ;
    
     public String getName() {
      return name;
     }
    
     public void setName(String name) {
      this.name = name;
     }
    
    }
    /************* "Department.java" *********/
    public class Department{
     Person person = new Person();//Person is the 'collaborator'- a fancy name for third party object
     
     public String getPersonName(){
      return person.getName();
     }
    }
    
    /************* "DepartmentTest.java" *********/
    public class DepartmentTest {
     @Test
     public void testGetNameCalls(){
      Department dept  = new Department();
      
      new MockUp(){
       @Mock //A directive to JMockit to redefine the method. Remember!! 
       public String getPersonName(){
        return null;
       }
          
      };
      String name = dept.getPersonName();//this call returns a null because of redefinition
      assertNull(name);
     }
    }
    
There are some more cool features of JMockit like Deencapsulation, "any" fields, Cascading mocks.... Will be writing about all this soon. Thanks for reading! Please comment!

14 comments:

  1. great post...much more comprehensive then the official tutorial

    ReplyDelete
  2. Very nicely written, helped me a lot

    ReplyDelete
  3. Your tutorials are very helpful.. Thanks abhi :)

    ReplyDelete
  4. Nice post, it really helpful to understand Jmockit.

    ReplyDelete
  5. Good stuff Abhi!
    Couple links you provided are giving 404...sure, difficult to update old links...:)

    ReplyDelete
  6. new MockUp…
    Do we suppose to make the Department as department when Mocking or it is just a typo?
    Thanks for the tutorial though.

    ReplyDelete
    Replies
    1. believe its a typo...
      http://jmockit.org/api1x/mockit/MockUp.html

      Delete
  7. Hi Abhi,

    Myself Sundar, firstof all your blog is very useful to me. I have some clarifications as below as,


    Now, I have a one simple program as xml reading, I need to integrate JMockit to that, Could you please give some idea

    ReplyDelete
  8. Thank you for the such good examples :-)

    ReplyDelete