在创建以下ParentChildDetail类的模拟时遇到问题

时间:2017-07-25 08:56:03

标签: java junit powermock easymock

我必须模拟下面的ParentChildDetail类 在下面的类中只有一个构造函数是可用的,它是参数化的构造函数。但构造函数正在调用initilase()方法。所以当模拟对象时,它再次调用initilase()方法,它会击中db。 但我必须手动为JUNIT测试创建数据

    public class ParentChildDetail
    {
        private final String ALL_HQL = "hql query to fetch parent and child";
        private Map<Integer, Set<Child>> parentChildMapping = null;

        private Integer Id;
        private DateTime date;

        public ParentChildDetail( Integer Id, DateTime date ) throws HibernateException
        {
            this.Id = Id;
            this.date = date;
            initialise();
        }

        private void initialise() throws HibernateException
        {
            String[] paramNames =
            { "Id", "effectiveDate" };
            Object[] paramValues =
            { Id, date };
            List<Child> Childs = HibernateSession.query( ALL_HQL, paramNames, paramValues );

            for ( Child child : Childs )
            {
                if ( parentChildCache.get( child.getParentId() ) == null )
                {
                    Set<Child> val = new HashSet<>();
                    val.add( child );
                    parentChildCache.put( child.getParentId(), val );
                }
                else
                {
                    parentChildCache.get( child.getParentId() ).add( child );
                }
            }
        }

        public Map<Integer, Set<Child>> getParentChildCache()
        {
            return parentChildCache;
        }

        public void setParentChildCache( Map<Integer, Set<Child>> parentChildCache )
        {
            this.parentChildCache = parentChildCache;
        }

    }

但是在模拟参数化构造函数时再次调用initialise()

Here the sample code I am writing to mock


    Method initialize=ParentChildDetail.class.getDeclaredMethod( "initialise", noparams );
    Object[] args={1,new DateTime(new Date( "01/01/2017" ))};
    Constructor<ParentChildDetail> c=ParentChildDetail.class.getConstructor(Integer.class,org.joda.time.DateTime.class);
    ConstructorArgs constructorArgs = new ConstructorArgs(c,args);
    ParentChildDetail p= PowerMock.createMock( ParentChildDetail.class, constructorArgs,initialize );

在最后一行低于错误

    java.lang.RuntimeException: Failed to instantiate mock calling constructor: Exception in constructor
        at org.easymock.internal.ClassProxyFactory.createProxy(ClassProxyFactory.java:219)
        at org.easymock.internal.MocksControl.createMock(MocksControl.java:129)
        at org.easymock.internal.MocksControl.createMock(MocksControl.java:114)
        at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2220)
        at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2163)
        at org.powermock.api.easymock.PowerMock.createMock(PowerMock.java:108)
        at com.subex.rocps.routingratecalculator.ParentChildTest.getTrnIdOperatorMDLMap(ParentChildTest.java:88)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
    Caused by: java.lang.IllegalStateException
        at com.subex.spark.database.hibernate.util.HibernateSession.checkInitialised(HibernateSession.java:288)
        at com.subex.spark.database.hibernate.util.HibernateSession.getSessionFactory(HibernateSession.java:254)
        at com.subex.spark.database.hibernate.util.HibernateSession.query(HibernateSession.java:298)
        at com.subex.rocps.routingratecalculator.util.ParentElementCacheCreator.initialise(ParentElementCacheCreator.java:41)
        at com.subex.rocps.routingratecalculator.util.ParentElementCacheCreator.<init>(ParentElementCacheCreator.java:31)
        at com.subex.rocps.routingratecalculator.util.ParentElementCacheCreator$$EnhancerByCGLIB$$ba31f8d9.<init>(<generated>)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at org.easymock.internal.ClassProxyFactory.createProxy(ClassProxyFactory.java:207)
        ... 29 more

1 个答案:

答案 0 :(得分:0)

正如评论者所说,调用数据访问层作为构建类的副作用的方法可能是反模式。无论如何,它使得单元测试很难。在这种情况下出现困难是因为ParentChildDetail()调用ParentChildDetail.initialise()HibernateSession.query()调用ParentChildDetail,因为这是一个静态方法,测试它有点棘手。

以下测试用例使用EasyMock(因为这是您的问题标记的)和PowerMock以便于实例化@RunWith(PowerMockRunner.class) @PrepareForTest(HibernateSession.class) public class ParentChildDetailTest { @Test public void testSomething() { PowerMock.mockStatic(HibernateSession.class); Integer id = 1234; DateTime date = new DateTime(); // not sure what you want to retrieve here, maybe nothing, maybe some particular children so // that you can test the behaviour of the initialise() method List<Child> children = new ArrayList<>(); expect(HibernateSession.query(anyString(), (String[]) anyObject(), (Object[]) anyObject())) .andReturn(children); PowerMock.replay(HibernateSession.class); ParentChildDetail parentChildDetail = new ParentChildDetail(id, date); // parentChildDetail has now been successfully constructed/initialised and it is available for use in your test ... } }

Util myUtil = DaggerMyComponent.builder().withAddress(txtAddress.getText()).build().getComponent().getUtil();

此代码适用于EasyMock v3.4,PowerMock v1.6.1 +和Junit 4.12

使用PowerMock here进行模拟的详细信息。

有关集成JUnit,EasyMock和PowerMock here的详细信息。