使用jndi-simple api获取数据源后,Junit测试中的NullPointerException

时间:2015-04-17 19:43:54

标签: java unit-testing maven junit jndi

我正在尝试创建并运行针对我的Servlet的单元测试,该Servlet在通过一些在线教程后访问DataSource 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容器中配置了DataSource,它运行正常,没有任何问题。我可以在我的JSP webapp中检索和显示数据而不会出现任何问题。

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 /测试/资源/ 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 /测试/资源/ 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);
    }

}

1 个答案:

答案 0 :(得分:0)

我们遇到这个问题有两个原因:JNDI为多个数据源定义了相同的名称;包含的密码&#39;#&#39;破坏JNDI的信件