Maybe this is a stupid question, but somebody have to pose stupid questions also...
Is it at all possible to JUnit-test Spring controllers with JUnit but without HttpUnit and/or Cactus? And if it is, are there any "best practice"?
Maybe this is a stupid question, but somebody have to pose stupid questions also...
Is it at all possible to JUnit-test Spring controllers with JUnit but without HttpUnit and/or Cactus? And if it is, are there any "best practice"?
Sincerely,
/The Cantor
"Murphy was an optimist"
(The O'Toole commentary on Murphy's Law)
Yes, it's quite easy:
1. create controller and populate its properties or constructor args in your JUnit test
2. drive its public entry method using a mock request and response
Here's a simple example. You'll need spring-mock.jar in your classpath.
Controller Test:
More examples can be found in AppFuse: http://tinyurl.com/6ansyCode:package org.appfuse.web; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import junit.framework.TestCase; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockServletContext; import org.springframework.web.context.support.XmlWebApplicationContext; import org.springframework.web.servlet.ModelAndView; public class UserControllerTest extends TestCase { private static Log log = LogFactory.getLog(UserControllerTest.class); private XmlWebApplicationContext ctx; public void setUp() { String[] paths = {"/WEB-INF/applicationContext*.xml", "/WEB-INF/action-servlet.xml"}; ctx = new XmlWebApplicationContext(); ctx.setConfigLocations(paths); ctx.setServletContext(new MockServletContext("")); ctx.refresh(); } public void testGetUsers() throws Exception { UserController c = (UserController) ctx.getBean("userController"); ModelAndView mav = c.handleRequest((HttpServletRequest) null, (HttpServletResponse) null); Map m = mav.getModel(); assertNotNull(m.get("users")); assertEquals(mav.getViewName(), "userList"); } }
HTH,
Matt
Wow!
That's amazingly easy, can't wait to get back to work to try it.
Thanks!
Sincerely,
/The Cantor
"Murphy was an optimist"
(The O'Toole commentary on Murphy's Law)
As Rod suggests, you can also test your controllers w/o talking to Spring's ApplicationContext at all. For instance, here's the same test using Easy Mock.
Code:public class UserControllerEMTest extends TestCase { private static Log log = LogFactory.getLog(UserControllerEMTest.class); private MockControl control = null; private UserManager mockManager = null; private UserController c = null; protected void setUp() throws Exception { control = MockControl.createControl(UserManager.class); mockManager = (UserManager) control.getMock(); c = new UserController(); c.setUserManager(mockManager); } public void testGetUsers() throws Exception { mockManager.getUsers(); control.setReturnValue(new ArrayList()); control.replay(); ModelAndView mav = c.handleRequest((HttpServletRequest) null, (HttpServletResponse) null); Map m = mav.getModel(); assertNotNull(m.get("users")); assertEquals(mav.getViewName(), "userList"); control.verify(); } }
OK. Is this the easymock-package that you are using here?
Sincerely,
/The Cantor
"Murphy was an optimist"
(The O'Toole commentary on Murphy's Law)
Yes, from http://easymock.org. The code above uses EasyMock 1.1 (download).Originally Posted by kantorn
OK.
Many thanks!
Sincerely,
/The Cantor
"Murphy was an optimist"
(The O'Toole commentary on Murphy's Law)
I've got my web app built with spring 1.1.1 where Dao implemented with iBatis 2.x. DataSource is jdbc based, where all credentials placed into jdbc.properties file. Below is the fragment from the dataAccessContext-local.xml file. It works fine. All xml files are in /WEB-INF/classes folder. So by default, they are visible to the Tomcat classloader. All spring context files, including the mock context are listed in web.xml file. All dependent libraries in /WEB-INF/lib folder.
The problem appears if I use Cactus bundled with that web app. When I'm trying to deploy this test web app, I've got the error message, where all jdbc credentials are not substituted by the jdbc.properties values and treated by dbcp as is, so they look similar to the below:
${jdbc.driverClassName}
....
${jdbc.password}
Question: Why jdbc.properties values are not visible when running with Cactus???
Thanks in advance!!!
------------------------------------------------------------------------------
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.Pr opertyPlaceholderConfigurer">
<property name="location"><value>classpath:jdbc.properties</value></property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>${jdbc.driverClassNa me}</value></property>
<property name="url"><value>${jdbc.url}</value></property>
<property name="username"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
<property name="validationQuery"><value>select 1 from dual</value></property>
</bean>
Also, in terms of configuring mock HttpServletRequest objects, you can also subclass MockHttpServletRequest and provide your own setParameters(Map) method that simply calls addParameters -- since addParameters doesn't follow bean name conventions.
You can then configure mock http request objects in Spring instead of having request parameters set using Java code in a JUnit.
e.g.
Code:<bean id="base-post" class="com.myco.test.MockRequest"> <property name="method"><value>POST</value></property> <property name="session"><ref local="test-session"/></property> <property name="servletPath"><value>/myapp</value></property> </bean> <bean id="myPost" parent="base-post" singleton="false"> <property name="requestURI"><value>do-something.htm</value></property> <property name="parameters"> <props> <prop key="_target3">Find</prop> </props> </property> </bean>