XNSIO
  About   Slides   Home  

 
Managed Chaos
Naresh Jain's Random Thoughts on Software Development and Adventure Sports
     
`
 
RSS Feed
Recent Thoughts
Tags
Recent Comments

Different Techniques to Stub/Mock Dependencies

I’ve primarily used the following techniques to stub/mock out dependent classes while unit testing:

  • Using a Dynamic Mocking Framework like Mockito, EasyMock, JMock, RhinoMock, etc
  • Create a special subclass of the dependent class (or Interface) in the test package and use that to stub out dependency
    • One can choose to create an anonymous inner class if a full new class in a separate file cannot be justified as an act of sanity.
    • (Sometimes you might even subclass the class under test to inject behavior and dependency).
  • Have the test implement or extend the dependent class

Let’s see each technique in action with an example:

Problem: We are building a Coffee Vending Machine controlling software and trying to test drive the Controller piece.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Controller {
    private Panel panel;
 
    public Controller(final Panel panel) {
        this.panel = panel;
        //some start up logic here.
        panel.display("Please select a coffee type");
    }
 
    public void selectedCoffee(final CoffeeType type) {
        String price = "0.35$"; // some logic to compute price
        panel.display("Please insert " + price);
    }
}

Controller does whatever magic it wants to do and then displays some message on the panel.

1
2
3
public interface Panel {
    void display(String msg);
}

1. One way to test the controller is by using a Dynamic Mocking framework like Mockito:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestUsingMockingFramework {
    private Panel panel = mock(Panel.class);
 
    @Test
    public void displayCoffeeSelectionMessageOnPowerUp() {
        new Controller(panel);
        verify(panel).display("Please select a coffee type");
    }
 
    @Test
    public void displayPriceOnSelectingCoffee() {
        Controller controller = new Controller(panel);
        controller.selectedCoffee(CoffeeType.BLACK);
        verify(panel).display("Please insert 0.35$");
    }
}

2. Another technique is to create a TestPanel class in the testing folder:

1
2
3
4
5
6
7
8
class TestPanel implements Panel {
    public String msg;
 
    @Override
    public void display(final String msg) {
        this.msg = msg;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestUsingHandCodedStub {
    private TestPanel panel = new TestPanel();
 
    @Test
    public void displayCoffeeSelectionMessageOnPowerUp() {
        new Controller(panel);
        assertEquals("Please select a coffee type", panel.msg);
    }
 
    @Test
    public void displayPriceOnSelectingCoffee() {
        Controller controller = new Controller(panel);
        controller.selectedCoffee(CoffeeType.BLACK);
        assertEquals("Please insert 0.35$", panel.msg);
    }
}

3. If you don’t want the overhead of creating an extra TestPanel class, you can create an anonymous inner class instead.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TestUsingAnonymousInnerClass {
    private String msg;
    private Panel panel = new Panel() {
        @Override
        public void display(final String message) {
            msg = message;
        }
    };
 
    @Test
    public void displayCoffeeSelectionMessageOnPowerUp() {
        new Controller(panel);
        assertEquals("Please select a coffee type", msg);
    }
 
    @Test
    public void displayPriceOnSelectingCoffee() {
        Controller controller = new Controller(panel);
        controller.selectedCoffee(CoffeeType.BLACK);
        assertEquals("Please insert 0.35$", msg);
    }
}

4. One other technique I find useful sometimes is to have my test implement or extend the dependency (class or interface). So the test acts as the real dependency.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class TestUsingTestClassAsPanel implements Panel {
    private String msg;
 
    @Override
    public void display(final String message) {
        msg = message;
    }
 
    @Test
    public void displayCoffeeSelectionMessageOnPowerUp() {
        new Controller(this);
        assertEquals("Please select a coffee type", msg);
    }
 
    @Test
    public void displayPriceOnSelectingCoffee() {
        Controller controller = new Controller(this);
        controller.selectedCoffee(CoffeeType.BLACK);
        assertEquals("Please insert 0.35$", msg);
    }
}

I’ve seen very few people use the last technique. Personally I think it has a place and time.

When would I use this technique?

  • Sometimes this technique can be very simple (not worth introducing Dynamic Mocking Framework yet nor worth the over-head of extra test helper classes)
  • I find this technique particularly useful when I don’t want to expose some state on the dependent class.
  • This technique takes you more towards interaction based testing rather than state based testing.

    Licensed under
Creative Commons License