views:

307

answers:

1

I'm writing tests for an application using the iBatis DAO framework. The app is running in a java 1.4 environment, so I'm using legacy versions of everything (JDK 1.4, JUnit3, iBatis 2.3 and JMock 1.2).

In my MockObjectTestCase subclass I have this test

public void testInsert() throws Exception {
    Mock mockDao = mock(TblPpvFiltersDao.class);
    mockDao.expects(once()).method("insert");

    Mock mockDaoManager = mock(DaoManager.class);
    mockDaoManager.expects(once()).method("getDao")
            .with(eq(TblPpvFiltersDao.class))
            .will(returnValue((TblPpvFiltersDao) mockDao.proxy()));

    PpvFiltersService service = new PpvFiltersServiceImpl(
            (DaoManager) mockDaoManager.proxy());

    service.insert(new PpvFiltersVO());        
}

which should verify that the service object will ask the DaoManager for a DAO object and call the insert method on it. The test fails with the error message

...DynamicMockError: mockDaoManager: tried to return an incompatible value: 
   expected a com.ibatis.dao.client.Dao but returned a $Proxy0

Trying to cast the mockDao object either to either com.ibatis.dao.client.Dao or com.ibatis.dao.client.template.SqlMapDaoTemplate ends in a ClassCastException.

What am I missing?

Update: nothing changes converting the code to use JDK 1.6, JUnit 4 and JMock2. This code

@Test
public void testInsert() throws Exception {
    final PpvFiltersVO theFilter = new PpvFiltersVO(new Integer(42));
    final TblPpvFiltersDao mockDao = context.mock(TblPpvFiltersDao.class);
    final DaoManager mockDaoManager = context.mock(DaoManager.class);

    context.checking(new Expectations() {{ 
        oneOf (mockDaoManager).getDao(TblPpvFiltersDao.class);
                               will(returnValue(mockDao));
        oneOf (mockDao).insert(theFilter);
    }});

    PpvFiltersService service = new PpvFiltersServiceImpl(mockDaoManager);

    service.insert(theFilter);
}

results in this error message:

java.lang.IllegalStateException: tried to return a $Proxy6 from a method 
    that can only return a com.ibatis.dao.client.Dao

maybe I'm missing something obvious here, but the code above comes almost straight from the JMock examples at http://www.jmock.org/getting-started.html.

Any ideas?

Fixed Of course it was something obvious. TblPpvFiltersDao above needs to extend the com.ibatis.dao.client.Dao marker interface. D'oh.

A: 

Remove the .proxy() call on mockDao. You want getDao() to return mockDao and not a proxy.

Also, it seems that you are using JMock 1. I suggest that you to move JMock which has a better API (or even to Mockito whose protocol is even simpler). In JMock2, you create a context object (instance of Mockery) from which you create mock object which are actual instances of your class (and not just instance of the Mock type).

Mockery ctx = new Mockery();
TblPpvFiltersDao dao = ctx.mock(TblPpvFiltersDao.class);
DaoManager daoManager = ctx.mock(DaoManager.class);

...

See http://www.jmock.org/getting-started.html for more details.

Itay
Nope, leaving out the .proxy() part I would get a org.jmock.Mock which is not what I want.
agnul
Why? If mockDaoManager returns mockDao, you can then test the expectation that mockDao.insert() is called. That's the point of the test, isn't it?
Matthew Flynn
This is JMock 1.2, so both mockDaoManager and mockDao are instances of org.jmock.Mock. The proxy() call is needed to get the "real" mock object. See http://www.jmock.org/jmock1-getting-started.html
agnul
@agnul,I just realized that and added a few sentences about that.
Itay