Anu*_*hna 8 java junit unit-testing ejb
当我尝试模拟以下方法(方法是使用业务逻辑的远程EJB调用)进行Junit测试时,它给出了javax.naming.NoInitialContextException
private void someMethod(int id1, int id2, HashMap map){
......some code........
Context ctx = new InitialContext();
Object ref = ctx.lookup("com.java.ejbs.MyEJB");
EJBHome ejbHome = (EJBHome)PortableRemoteObject.narrow(ref, EJBHome.class);
EJBBean ejbBean = (EJBBean)PortableRemoteObject.narrow(ejbHome.create(), EJBBean.class);
ejbBean.someMethod(id1,name);
.......some code.......}
Run Code Online (Sandbox Code Playgroud)
我对上述方法的单元测试
@Test
public void testsomeMethod() throws Exception {
.......setting initial code...
//Mock context and JNDI
InitialContext cntxMock = PowerMock.createMock(InitialContext.class);
PowerMock.expectNew(InitialContext.class).andReturn(cntxMock);
expect(cntxMock.lookup("com.java.ejbs.MyEJB")).andReturn(refMock);
..........some code..........
PowerMock.replayAll();
Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map);
}
Run Code Online (Sandbox Code Playgroud)
当Whitebox.invokeMethod(ObjectOfsomeMethodClass,"someMethod",id1,id2,map)方法调用它时,它会给出以下异常.
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
Run Code Online (Sandbox Code Playgroud)
我相信,虽然我们在test方法中模拟了Context,但在调用Whitebox.invokeMethod(ObjectOfsomeMethodClass,"someMethod",id1,id2,map)方法时它并没有使用mock对象,而是试图调用Context ctx = new InitialContext(); 原始方法中的方法(someMethod).
手工制造
正如InitialContext
doc所说,您可以InitialContext
使用java.naming.factory.initial
系统属性为对象提供自己的工厂.当代码在应用程序服务器内运行时,系统属性由服务器设置.在我们的测试中,我们提供了自己的JNDI实现.
这是我的Mockito唯一的解决方案:我定义了一个自定义InitialContextFactory
类,它返回一个模拟InitialContext
.您可以根据需要自定义模拟,可能会在lookup
调用时返回更多模拟.
public class PlainTest {
@Mock InitialContextFactory ctx;
@InjectMocks Klasa1 klasa1;
public static class MyContextFactory implements InitialContextFactory
{
@Override
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
ConnectionFactory mockConnFact = mock(ConnectionFactory.class);
InitialContext mockCtx = mock(InitialContext.class);
when(mockCtx.lookup("jms1")).thenReturn(mockConnFact);
return mockCtx;
}
}
@Before
public void setupClass() throws IOException
{
MockitoAnnotations.initMocks(this);
System.setProperty("java.naming.factory.initial",
this.getClass().getCanonicalName() + "$MyContextFactory");
}
Run Code Online (Sandbox Code Playgroud)
春天(编辑添加)
如果你不介意利用Spring Framework进行测试,那么这是他们的简单解决方案:SimpleNamingContextBuilder:
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
DataSource ds = new DriverManagerDataSource(...);
builder.bind("java:comp/env/jdbc/myds", ds);
builder.activate();
Run Code Online (Sandbox Code Playgroud)
可以把它放入@Before
或@BeforeClass
.之后activate()
,jndi数据将从spring dummy中拉出来.
小智 1
您可以重构代码并在新方法中提取上下文的初始化。
private void someMethod(int id1, int id2, HashMap map){
......some code........
Context ctx = getInitialContext();
Object ref = ctx.lookup("com.java.ejbs.MyEJB");
EJBHome ejbHome = (EJBHome)PortableRemoteObject.narrow(ref, EJBHome.class);
EJBBean ejbBean = (EJBBean)PortableRemoteObject.narrow(ejbHome.create(), EJBBean.class);
ejbBean.someMethod(id1,name);
.......some code.......}
Run Code Online (Sandbox Code Playgroud)
你的测试代码将是这样的:
Context mockContext = mock(Context.class);
doReturn(mockContext).when(yourclass).getInitalContext();
...... some code....
Run Code Online (Sandbox Code Playgroud)