【问题标题】:NullPointerException in Junit testing after using jndi-simple api for getting datasource使用 jndi-simple api 获取数据源后 Junit 测试中的 NullPointerException
【发布时间】:2015-04-17 19:43:54
【问题描述】:

我正在尝试针对我的 Servlet 创建和运行单元测试,该 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 容器中配置了 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/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);
    }

}

【问题讨论】:

    标签: java unit-testing maven junit jndi


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-14
      • 1970-01-01
      相关资源
      最近更新 更多