Saturday Aug 31

Key Concepts

Easymock tutorial

PDFPrintE-mail
Wednesday, 20 April 2011 09:49
AddThis Social Bookmark Button

Introduction

In unit testing, mock objects can simulate the behavior of complex, real objects and are therefore useful when a real object is impossible to incorporate into your unit test. If an object has any of the following characteristics, it may be useful to use a mock object in its place:

 

  • supplies non-deterministic results (e.g. the current time or the current temperature);
  • has states that are difficult to create or reproduce (e.g. a network error or database error) or in integration test
  • is slow (e.g. a large network resource); 
  • does not yet exist (test driven development) or may change behavior; 
  • would have to include information and methods exclusively for testing purposes.

In this mock testing tutorial i will use and recommend EasyMock because it's a complete and well documented framework.

Features

Easymock features :

 

  • Invocation count constraints
  • Recording strict expectations
  • Partial mocking
  • No extra "prepare for test" code
  • No need to use @RunWith annotation or base test class
  • Easier argument matching based on properties of value objects

Requirements

Itemversion
Easymock 3   version 3.0
Maven  version 3.0.3
Junit  version 4.8.2
Apache Commons Lang version 2.6
Maven cobertura Plugin version 2.5

     

    Mock Objects

    In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways. A computer programmer typically creates a mock object to test the behavior of some other object, in much the same way that a car designer uses a crash test dummy to simulate the dynamic behavior of a human in vehicle impacts.

    Test driven approach

    In test driven design, we develop the unit test before the functionality. We write a test that verifies that the class should do X after our call. We prove that the test fails, we then create the component to make the test pass. 

    Requirement scenario

    Let's imagine we are developping a car with a manual transmission. But our car is not a basic car, is a smart car. You are not allowed to change gear if you don't press the clutch otherwise you get a GearBoxException. 

    User Story 

    I want a car preventing me to change gear if i don't press the clutch before 

    Test scenario 1 - Normal scenario 

    1. Press the clutch pedal and hold it to the floor
    2. Move the gear shift to first gear
    3. Release the clutch pedal 
    4. Press the clutch pedal and hold it to the floor
    5. Move the gear shift to neutral gear
    6. Release the clutch pedal 

    Test scenario 1 - Exception 

    1. Try to move the gear shift to first gear
    2. The gearbox should throw an exception

    Objects involved

    First of all the Car object. It's the object we want to test. The gearbox object and the clutch are not part of the test. We will explain how to replace them with EasyMock Mock Objects.

    The Gear Box 

    Gear Box - Easymock tutorial

    public class GearBox {
        
        private Gear currentGear = Gear.NEUTRAL;
        
        public void changeUp(){
            currentGear = currentGear.up();
        }
    
        public void changeDown(){
            currentGear = currentGear.previous();
            
        }
        public Gear getCurrent(){
            return currentGear;
        }
    
    }
    

    Gear enumeration

    Gear enumeration defining the gear up and down according to the current state

    Spring java source

    public enum Gear {
        NEUTRAL(0),
        ONE(1),
        TWO(2),
        THREE(3),
        FOUR(4),
        FIVE(5);
        
        int level;
        
        private Gear(int level){
            this.level = level; 
        }
        
        public Gear down(){
            if (this == NEUTRAL) return NEUTRAL;
            return resolve (this.level-1);
            
        }
        
        public Gear up(){
            if (this == FIVE) return FIVE;
            return resolve (this.level+1);
        }
        
        private Gear resolve (int level){
            for (Gear current : Gear.values()) {
                if (current.level == level) return current;
            }
            return null;
            
        }
    }
    

    Abstract Pedal

    Abstract pedal object keeping the current state of the pedal

    Gear Box - Easymock tutorial

    public abstract class AbstractPedal {
        private PedalState state = PedalState.RELEASED;
        
        public void press(){
            state = PedalState.PRESSED;
        }
        public void release(){
            state = PedalState.RELEASED;
        }
        
        public PedalState getState(){
            return state;
        }
    }
    

    Pedal state

    Gear Box - Easymock tutorial

    public enum PedalState {
        PRESSED,
        RELEASED;
    }
    

    Gas Pedal

    Gear Box - Easymock tutorial

    public class GasPedal extends AbstractPedal {}
    

    Clutch Pedal

    Gear Box - Easymock tutorial

    public class ClutchPedal extends AbstractPedal {}
    

    First EasyMock test

    Let's see our Normal test scenario implemented with EasyMock.

    Spring java source

        //Execute the scenario
        car.releaseGas();
        car.pressClutch();
        car.shiftGearUp();
        car.releaseClutch();
        car.pressGas();
    
        //Verify that the first gear is engaged
        assertEquals(Gear.ONE, gearBox.getCurrent());
        
        car.releaseGas();
        car.pressClutch();
        car.shiftGearDown();
        car.releaseClutch();
        car.pressGas();
    
        //Verify that you are in neutral
        assertEquals(Gear.NEUTRAL, gearBox.getCurrent());
    

    Mock objects setup and tear down

    In this chapter we will setup the mock objects to replace the context needed to test our car 

     Easymock setup and teardown

    	@Before
    	public void setup(){
    		gearBox = createMock(GearBox.class);
    		clutchPedal= createMock(ClutchPedal.class);
    		gasPedal= createMock(GasPedal.class);
    		car = new Car(gearBox,clutchPedal,gasPedal);
    	}
    	@After 
    	public void tearDown(){
    		gearBox = null;
    		clutchPedal = null;
    		car = null;
    	}
    

    Test expectation and assertion 

    Let's define what we expect and assert according to the first scenario  using EasyMock.

     

    Gear Box - Easymock tutorial

        /**
         * Gear Up
         */
        //The gas pedal should be released
        gasPedal.release(); 
         //The clutch pedal should be pressed
        clutchPedal.press();
        //The state of the clutch pedal should be pressed
        expect(clutchPedal.getState()).andReturn(PedalState.PRESSED).once();
        //ChangeUp method shoud be called on GearBox object 
        gearBox.changeUp();
        //The state of the clutch pedal should be pressed
        expect(gearBox.getCurrent()).andReturn(Gear.ONE).once();
        //The clutch pedal should be release
        clutchPedal.release();
        //The state of the clutch pedal should be released
        //expect(clutchPedal.getState()).andReturn(PedalState.RELEASED).once();
        //The gas pedal should be pressed
        gasPedal.press();
            
        /**
         * Gear Down
         */
        //The gas pedal should be released
        gasPedal.release();
        //The clutch pedal should be pressed
        clutchPedal.press();
        //The state of the clutch pedal should be pressed
        expect(clutchPedal.getState()).andReturn(PedalState.PRESSED).once();
        //ChangeDown method shoud be called on GearBox object 
        gearBox.changeDown();
        //The state of the clutch pedal should be pressed
        expect(gearBox.getCurrent()).andReturn(Gear.NEUTRAL).once();
        //The clutch pedal should be release
        clutchPedal.release();
        //The state of the clutch pedal should be released
        //The gas pedal should be pressed
        gasPedal.press();
    

    Test execution

    Easymock tests use the following lifecycle : 

     

    1. Expectation and assertion stage definition
    2. Replay the mock objects
    3. Execute the scenario
    4. Verify expectations on mock objects
    5. Reset the mock objects (optional)

    Gear change test 

    Lets take a look at the complete gear change test scenario implementation

     

    Gear Box - Easymock tutorial

    @Test
    public void testChangeGear(){
        
        /**
         * Gear Up
         */
        //The gas pedal should be released
        gasPedal.release();
        //The clutch pedal should be pressed
        clutchPedal.press();
        //The state of the clutch pedal should be pressed
        expect(clutchPedal.getState()).andReturn(PedalState.PRESSED).once();
        //ChangeUp method shoud be called on GearBox object 
        gearBox.changeUp();
        //The state of the clutch pedal should be pressed
        expect(gearBox.getCurrent()).andReturn(Gear.ONE).once();
        //The clutch pedal should be release
        clutchPedal.release();
        //The state of the clutch pedal should be released
        //expect(clutchPedal.getState()).andReturn(PedalState.RELEASED).once();
        //The gas pedal should be pressed
        gasPedal.press();
    
        
        /**
         * Gear Down
         */
        //The gas pedal should be released
        gasPedal.release();
        //The clutch pedal should be pressed
        clutchPedal.press();
        //The state of the clutch pedal should be pressed
        expect(clutchPedal.getState()).andReturn(PedalState.PRESSED).once();
        //ChangeDown method shoud be called on GearBox object 
        gearBox.changeDown();
        //The state of the clutch pedal should be pressed
        expect(gearBox.getCurrent()).andReturn(Gear.NEUTRAL).once();
        //The clutch pedal should be release
        clutchPedal.release();
        //The state of the clutch pedal should be released
        //The gas pedal should be pressed
        gasPedal.press();
    
        
        replay(gearBox);
        replay(clutchPedal);
        replay(gasPedal);
    
        //Execute the scenario
        car.releaseGas();
        car.pressClutch();
        car.shiftGearUp();
        car.releaseClutch();
        car.pressGas();
    
        //Verify that the first gear is engaged
        assertEquals(Gear.ONE, gearBox.getCurrent());
        
        car.releaseGas();
        car.pressClutch();
        car.shiftGearDown();
        car.releaseClutch();
        car.pressGas();
        
        //Verify that you are in neutral
        assertEquals(Gear.NEUTRAL, gearBox.getCurrent());
        
        verify(gearBox);
        verify(clutchPedal);
    }    
    

    Gear change exception test 

    Lets take a look at the gear change exception test.In this scenario we want that the Car class throw GearBoxException if we try to change gear without pressing the clutch pedal before. We catch the expected exception and if we don't fall in the catch clause we return the test as failing.

     

    Gear Box - Easymock tutorial

    @Test
    public void testGearBoxException(){
        //The state of the clutch pedal should be pressed
        expect(clutchPedal.getState()).andReturn(PedalState.RELEASED).once();
        
        replay(gearBox);
        replay(clutchPedal);
    
        //Execute the scenario 
        try {
            car.shiftGearUp();
            fail("A gear box exception should be thrown in you dont press de clutch");
        } catch (GearBoxException e) {
            //Good
        }
        verify(gearBox);
        verify(clutchPedal);
    } 
    

    Test coverage report

    Let's begin with the generated Cobertura output. Figure 1 shows a report produced by running Cobertura code coverate on the our test suite. You can see that coverage is 100 percent on Car and especially on the GearBoxException we wanted to test in the second scenario

    Test Classes

    • AbstractPedal (0%)
    • Car (100%)
    • ClutchPedal (0%)
    • GasPedal (0%)
    • Gear (94%)
    • GearBox (0%)
    • PedalState (100%)
    Figure 1

     

     
     1  
     /**
     2  
      * 
     3  
      */
     4  
     package ch.javatutorial.samples.car;
     5  
     
     6  
     import org.apache.commons.lang.NullArgumentException;
     7  
     
     8  
     import ch.javatutorial.samples.car.exception.GearBoxException;
     9  
     
     10  
     /**
     11  
      * 
     12  
      * 
     13  
      * @author sursini
     14  
      *
     15  
      */
     16  
     public class Car {
     17  
             
     18  
             private final GearBox gearBox;
     19  
             private final ClutchPedal clutchPedal;
     20  
             private final GasPedal gasPedal;
     21  
             
     22  
             public Car(GearBox gearBox,ClutchPedal clutchPedal,GasPedal gasPedal) {
     23  2
                     super();
     24  2
      if (gearBox == null) throw new NullArgumentException("gearbox");
     25  2
      if (clutchPedal == null) throw new NullArgumentException("clutch pedal");
     26  2
      if (gasPedal == null) throw new NullArgumentException("gas pedal");
     27  2
                     this.gearBox = gearBox;
     28  2
                     this.clutchPedal = clutchPedal;
     29  2
                     this.gasPedal = gasPedal;
     30  2
             }
     31  
     
     32  
             public void shiftGearUp(){
     33  2
      if (clutchPedal.getState() == PedalState.RELEASED) throw new GearBoxException();
     34  1
                     gearBox.changeUp();
     35  1
             }
     36  
             
     37  
             public void shiftGearDown(){
     38  1
      if (clutchPedal.getState() == PedalState.RELEASED) throw new GearBoxException();
     39  1
                     gearBox.changeDown();
     40  1
             }
     41  
     
     42  
             public void pressClutch(){
     43  2
                     clutchPedal.press();
     44  2
             }
     45  
     
     46  
             public void releaseClutch(){
     47  2
                     clutchPedal.release();
     48  2
             }
     49  
             
     50  
             public void pressGas(){
     51  2
                     gasPedal.press();
     52  2
             }
     53  
     
     54  
             public void releaseGas(){
     55  2
                     gasPedal.release();
     56  2
             }
     57  
     
     58  
             
     59  
     }


    Summary

    Mock objects are a powerful technique for helping to obtain high levels of test coverage for your code without much of the stress associated with resolving dependencies. It allows the behavior of collaborators of your classes under test to be specified with relatively little effort and a great amount of control. EasyMock is a particular powerful framework for applying mock objects in practice.

    The aim of this article has been to help new users overcome the initial hurdles necessary for putting EasyMock to work in testing their applications. It has also covered some details of the framework in action, starting with the simple use of EasyMock life cycle methods.

    If you have any remark or questions feel free to put a comment.If you enjoyed this tutorial and want to promote it don't hesitate to click on

     

    Tags: test, objects, version, mock, object, easymock, gear, clutch

    Comments  

     
    0 #3 Spring Developer 2013-03-21 13:46
    Great tutorial 8)
    Thanks that you took excellent example with a car in this article!
    But unfortunately maven plugin for a code coverage explained not very clear =(
    Quote
     
     
    0 #2 Romi 2013-01-21 08:20
    Thanks for this short and crisp introduction to EasyMock.
    I was trying to test the anonymous classes through easymock.
    Consider the following snippet:

    class Presenter {

    private Display display;

    public Presenter(Displ ay display) {
    this.display = display;
    display.getButton().addClickHandler (new ClickHandler() {
    public void onClick() { // do something }
    });
    }
    }

    I need to test this onClick event using EasyMock. Any pointers on how this can be tested or how to send a mock click event?
    Quote
     
     
    +2 #1 vasilaras 2012-04-14 10:26
    Finally with this, i understand the mock use! Thanks!
    Quote
     

    Add comment


    Security code
    Refresh

    Java Tutorial on Facebook