Apache Wicket is a component based web application framework which offers good unit testing capabilities. This blog entry describes how you can use those capabilities to mock beans which are injected by using the Spring integration of Apache Wicket (Note: The precondition of this blog entry is that you are using Apache Wicket 1.5).
The WicketApplication class of my example application is pretty simple. It only configures the homepage of my application and enables the @SpringBean annotation support. The source code of the WicketApplication class is following:
public class WicketApplication extends WebApplication { /** * @see org.apache.wicket.Application#getHomePage() */ @Override public Class<HomePage> getHomePage() { return HomePage.class; } /** * @see org.apache.wicket.Application#init() */ @Override public void init() { super.init(); //Enable SpringBean annotation support. getComponentInstantiationListeners().add(new SpringComponentInjector(this)); } }
The homepage of my application is pretty simple as well. It simply fetches a message by using the injected Spring bean and inserts the returned message to the home page by using the Label component. The source code of the HomePage class is following:
public class HomePage extends WebPage { protected static final String WICKET_ID_HELLO_MESSAGE = "helloMessage"; @SpringBean private MessageService messageService; public HomePage(final PageParameters parameters) { super(parameters); } @Override protected void onInitialize() { super.onInitialize(); String messageText = messageService.getMessage(); Label message = new Label(WICKET_ID_HELLO_MESSAGE, messageText); this.add(message); } public void setMessageService(MessageService messageService) { this.messageService = messageService; } }
The MessageService interface has only one method which is used to obtain a message text. The source code of the MessageService interface is following:
public interface MessageService { /** * Returns message text. * @return */ public String getMessage(); }
The actual bean class is called HelloMessageService and it returns a familiar message: Hello World! The source code of my bean class is following:
@Service public class HelloMessageService implements MessageService { protected static final String HELLO_MESSAGE = "Hello World!"; @Override public String getMessage() { return HELLO_MESSAGE; } }
I have now introduced the classes of my example application to you. I will describe next how you can mock the message service bean by using Mockito and write a unit test for the HomePage class. I have created an abstract base class called AbstractWicketTest which must be extended by the actual test classes. The base class initializes the WicketTester and ApplicationContextMock classes which can be used to test the Wicket components with mock objects. The source code of the AbstractWicketTest class is following:
public abstract class AbstractWicketTest { protected static final String BEAN_NAME_MESSAGE_SERVICE = "messageService"; private ApplicationContextMock applicationContextMock; private WicketTester tester = null; @Before public void setUp() throws Exception { //Creates a new application context mock. applicationContextMock = new ApplicationContextMock(); //Creates a new WicketTester tester = new WicketTester(); //Configures the SpringBean annotation support to use the mock application context. //This ensures that the mock objects are injected instead of the actual bean classes. tester.getApplication().getComponentInstantiationListeners().add(new SpringComponentInjector(tester.getApplication(), applicationContextMock)); setupTest(); } /** * Subclasses can use this method to provide the configuration needed by * each test. */ protected abstract void setupTest(); /** * Adds mock to the mock application context. * @param beanName The name of the mock bean. * @param mock The mock object. */ protected void addMock(String beanName, Object mock) { applicationContextMock.putBean(beanName, mock); } protected ApplicationContextMock getApplicationContextMock() { return applicationContextMock; } protected WicketTester getTester() { return tester; } }
The actual test class for the homepage of my example application is pretty simple. It extends the AbstractWicketTest class and uses the setupTest() method to:
- Create a MessageService mock object by using Mockito.
- Specify the behavior of the created mock object.
- Add the created mock object to the mock application context.
The HomePageTest class has also one test method called renderPage() which verifies that the home page is rendered correctly and that the interactions with the created mock object are correct. The source code of the test class is following:
public class HomePageTest extends AbstractWicketTest { private static String MESSAGE = "Hello!"; private MessageService messageServiceMock; @Override protected void setupTest() { //Creates Message service mock and specifies its behavior. messageServiceMock = mock(MessageService.class); when(messageServiceMock.getMessage()).thenReturn(MESSAGE); //Adds the created mock as a spring bean addMock(AbstractWicketTest.BEAN_NAME_MESSAGE_SERVICE, messageServiceMock); } @Test public void renderPage() { WicketTester tester = getTester(); tester.startPage(HomePage.class); verify(messageServiceMock, times(1)).getMessage(); verifyNoMoreInteractions(messageServiceMock); tester.assertComponent(HomePage.WICKET_ID_HELLO_MESSAGE, Label.class); tester.assertLabel(HomePage.WICKET_ID_HELLO_MESSAGE, MESSAGE); } }
I have now demonstrated to you how you can mock Spring beans by using Mockito when writing unit tests for Wicket components. As always, I have also created a simple example application which you can use as you see fit. Happy mocking!
Very well written and explained. Thanks a lot. Keep posting.!!!
Hi Sameer,
It is great to hear that this entry was useful to you!
Thanks a lot!
You are welcome. It is nice to know that even an old old blog entry can still be useful to someone.
Thanks for the guide! really useful
You are welcome!
The information is a bit old and that is why I am happy to hear that it was helpful to you.
Thanks for this well written howto.
I'm using Spring Security with wicket auth-role, and I have some @SpringBean annotation in my Session() class. Injection is done with Injector.get().inject(this) because Session isn't a Page.
All my unit tests are now failing because this injection seems to be not working with my mocked applicationContext.
How should I overwrite Injector.get().inject(this) in my uint test ?
Kind regards,
Bernard
After 3 years, you're probably not working on this subject... I'll post my question on the wicket mailing list.
Regards,
Hi,
I am sorry that I was a bit slow to answer to your comment (I am on holiday).
Anyway, I haven't been using Wicket for three years, and I have to confess that I don't know how you can solve your problem.
I hope that you get a better answer from the Wicket mailing list.
Hi!
I try "getComponentInstantiationListeners().add(new SpringComponentInjector(this));"
but error, please help! i use lib: Spring FrameWork 4.0.1, wicket 6.16.0
thanks you!
Hi,
Does the test throw an exception? If so, what exception does it throw?