Kiva
Kiva

Reputation: 9363

unit test with CDI Unit and EasyMock

I have a project with CDI and I would like to create unit test with mocks. To manage mocks, I would like to use EasyMock and to run with CDI, I find the cdi-unit project which seem easy to use.

I have a problem to get a mock with EasyMock in CDI context. Here is my unit test:

@RunWith(CdiRunner.class)
@AdditionalClasses(MockFactory.class)
public class ResultYearMServiceImplTest {

    @Inject
    private IStockDao stockDao;

    @Inject
    private ResultYearMServiceImpl resultYearMService;

    @Test
    public void getResultList() {
        EasyMock.reset(stockDao);
        EasyMock.expect(stockDao.getListStocks()).andReturn(null).once()
                .andReturn(new ArrayList<DtoStock>()).once();
        EasyMock.replay(stockDao);
    }
}

IStockDao needs to be mock in the test, so to get it I would like to use a @Produces method like this (in MockFactory class given to cdi unit by @AdditionalClasses):

@Produces
@ApplicationScoped
public IStockDao getStockDao() {
    return EasyMock.createMock(IStockDao.class);
}

When I run my unit test, the mock is good in unit test but I get this error:

java.lang.IllegalArgumentException: Not a mock: org.jboss.weld.proxies.IStockDao$-1971870620$Proxy$_$$_WeldClientProxy

This one comes because CDI doesn't give an instance of EasyMock IStockDao but a proxified instance and EasyMock doesn't accept this in these methods (like reset method).

So I replace @ApplicationScoped in MockFactory by @Dependent which doesn't proxified the instance but I have a new problem:

This annotation give a new instance of mock at each injection point so I can use it because I have a mock in the unit test to mock method called in the tested class. And this instance of mock must be the same in the tested class (it's not the case with @Dependent).

How can I get the same instance in the unit test and the tested class ?

Thanks.

Upvotes: 3

Views: 3581

Answers (3)

Bryn
Bryn

Reputation: 487

The next version of CDI-Unit (2.1.1) adds support for EasyMock in the same way that Mockito is currently supported.

Upvotes: 1

marciopd
marciopd

Reputation: 130

I was unit testing a CDI interceptor with easymock and had the same problem as you.

I would like to share the workaround I used. It consists in producing the mocks in @Dependent scope. This way we can get over the CDI proxy problem with easymock.

import static org.easymock.EasyMock.createStrictControl;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;


/**
 * Mock producer. Beans are produced in Dependent scope to not be proxied.
 */
@ApplicationScoped
public class CdiMockProducerUnitTests {

    /**
     * Mock
     */
    private final MyMockClass myMock;

    /**
     * Constructor creating mocks.
     */
    public CdiMockProducerTestesUnitarios() {
        myMock =  createStrictControl().createMock(MyMockClass.class);
    }

    /**
     * Produces mock in dependent scope.
     *
     * @return mock
     */
    @Produces
    @Dependent
    public MyMockClass produceMock() {
        return myMock;
    }

}

Upvotes: 1

Jan Galinski
Jan Galinski

Reputation: 12003

Needle is your friend for testing CDI.

http://needle.spree.de

public class ResultYearMServiceImplTest {
   @Rule
   public final NeedleRule needle = new NeedleRule();

   @Inject
   private IStockDao stockDao;

   @ObjectUnderTest
   private ResultYearMServiceImpl resultYearMService;
@Test
public void getResultList() {
    EasyMock.reset(stockDao);
    EasyMock.expect(stockDao.getListStocks()).andReturn(null).once()
            .andReturn(new ArrayList<DtoStock>()).once();
    EasyMock.replay(stockDao);
}
}

Upvotes: 3

Related Questions