我正在尝试通过访问以下网址的在线教程后,对访问数据源的Servlet创建并运行单元测试。
http://fandry.blogspot.com/2011/03/junit-based-integration-testing-with.html
注意:我过去有类似的帖子,从中得到了使用jndi-simple
api的想法,这是答案之一中建议的。
但是我在测试执行期间遇到以下异常。
例外
Running com.study.mockito.controllers.ProductControllerTest
Failed to bind JNDI context....
java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:514)
at org.osjava.sj.jndi.StaticHashtable.put(StaticHashtable.java:84)
at org.osjava.sj.jndi.AbstractContext.bind(AbstractContext.java:337)
at org.osjava.sj.jndi.AbstractContext.rebind(AbstractContext.java:361)
at org.osjava.sj.jndi.AbstractContext.rebind(AbstractContext.java:368)
at javax.naming.InitialContext.rebind(InitialContext.java:427)
at org.osjava.sj.jndi.DelegatingContext.rebind(DelegatingContext.java:76)
at javax.naming.InitialContext.rebind(InitialContext.java:427)
at com.study.mockito.controllers.ProductControllerTest.setUpClass(ProductControllerTest.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
我已经使用META-INF / context.xml在Tomcat容器中配置了数据源,并且它工作正常,没有任何问题。我能够在我的JSP Web应用程序中检索和显示数据,而没有任何问题。
context.xml
<Context antiJARLocking="true" path="/mockito-web">
<!-- PostgreSQL Datasource -->
<Resource auth="Container" driverClassName="org.postgresql.Driver" factory="org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory" maxActive="50" maxIdle="10" maxWait="-1" name="jdbc/istore-db" password="postgres" type="javax.sql.DataSource" url="jdbc:postgresql://mydb-server:5432/istore-db" username="postgres"/>
</Context>
pom.xml
<dependency>
<groupId>simple-jndi</groupId>
<artifactId>simple-jndi</artifactId>
<version>0.11.4.1</version>
<scope>test</scope>
</dependency>
src / test / resources / jndi.properties
java.naming.factory.initial=org.osjava.sj.SimpleContextFactory
org.osjava.sj.root=target/test-classes
org.osjava.jndi.delimiter=/
org.osjava.sj.jndi.shared=true
src / test / resources / jdbc.properties
istore-db.type=javax.sql.DataSource
istore-db.driver=org.postgresql.Driver
istore-db.url=jdbc:postgresql://mydb-server:5432/istore-db
istore-db.user=postgres
istore-db.password=postgres
ProductContollerTest.java
public class ProductControllerTest {
private HttpServletRequest request;
private HttpServletResponse response;
private ProductController controller;
private RequestDispatcher rd;
private ServletContext appContext;
private ProductService productService;
private Product product;
@BeforeClass
public static void setUpClass() {
try {
InitialContext ctxt = new InitialContext();
DataSource dataSource = (DataSource) ctxt.lookup("jdbc/istore-db");
// rebind for alias if needed
ctxt.rebind("jdbc/istore-db", dataSource);
} catch (Exception ex) {
System.out.println("Failed to bind JNDI context....");
ex.printStackTrace();
}
}
@Before
public void setUp() {
controller = new ProductController();
request = mock(HttpServletRequest.class);
response = mock(HttpServletResponse.class);
rd = mock(RequestDispatcher.class);
appContext = mock(ServletContext.class);
productService = mock(ProductService.class);
product = mock(Product.class);
}
@Test
public void testProcessRequest() throws ServletException, IOException {
when(productService.getProduct(anyInt())).thenReturn(product);
when(request.getServletContext()).thenReturn(appContext);
when(appContext.getRequestDispatcher(anyString())).thenReturn(rd);
//make an actual call
controller.doGet(request, response);
//verify that the method is getting called
verify(rd).forward(request, response);
}
}
ProductController.java
@WebServlet(name = "ProductController", urlPatterns = {"/product.htm"})
public class ProductController extends HttpServlet {
private static final int PRODUCT_ID = 301;
@Resource(name = "jdbc/istore-db")
protected DataSource dataSource;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
public void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Into the ProductController...");
//fetch the product from the db based on productId parameter
Product product = new ProductService(dataSource).getProduct(PRODUCT_ID);
request.setAttribute("product", product);
RequestDispatcher rd = request.getServletContext().getRequestDispatcher("/jsp/product.jsp");
rd.forward(request, response);
}
}
最佳答案
我们遇到此问题的原因有两个:JNDI为多个数据源定义了相同的名称;密码包含破坏JNDI的'#'字母