Unit testing 使用CDI单元和EasyMock进行单元测试

Unit testing 使用CDI单元和EasyMock进行单元测试,unit-testing,cdi,easymock,cdi-unit,Unit Testing,Cdi,Easymock,Cdi Unit,我有一个CDI项目,我想用mock创建单元测试。 为了管理mock,我想使用EasyMock并使用CDI运行,我发现CDI单元项目似乎很容易使用 在CDI上下文中,我无法使用EasyMock获得模拟。下面是我的单元测试: @RunWith(CdiRunner.class) @AdditionalClasses(MockFactory.class) public class ResultYearMServiceImplTest { @Inject private IStockDa

我有一个CDI项目,我想用mock创建单元测试。 为了管理mock,我想使用EasyMock并使用CDI运行,我发现CDI单元项目似乎很容易使用

在CDI上下文中,我无法使用EasyMock获得模拟。下面是我的单元测试:

@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);
    }
}
当我运行单元测试时,单元测试中的模拟很好,但我得到以下错误:

java.lang.IllegalArgumentException:不是模拟: org.jboss.weld.proxies.IStockDao$-1971870620$Proxy$\u$$\ uWeldClientProxy

这是因为CDI没有给出EasyMock IStockDao的实例,而是一个代理实例,EasyMock在这些方法中不接受这一点(比如重置方法)

因此,我将MockFactory中的@ApplicationScoped替换为@Dependent,它没有代理实例,但我有一个新问题:

该注释在每个注入点提供了一个新的mock实例,因此我可以使用它,因为在测试类中调用的单元测试到mock方法中有一个mock。这个mock实例在测试类中必须是相同的(与@Dependent不同)

如何在单元测试和测试类中获得相同的实例


谢谢。

针头是您测试CDI的朋友

public类resultyearmservicempltest{
@统治
公共最终针刺规则针=新针刺规则();
@注入
私有的IStockDao stockDao;
@被测对象
私有resultYearMService impl resultYearMService;
@试验
public void getResultList(){
EasyMock.reset(stockDao);
expect(stockDao.getListStocks()).andReturn(null.once())
.andReturn(新ArrayList()).once();
EasyMock.replay(stockDao);
}
}

我在用easymock对CDI拦截器进行单元测试,遇到了与您相同的问题

我想与大家分享我使用的解决方法。 它包括在@Dependent作用域中生成模拟。这样我们就可以用easymock解决CDI代理问题

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;
    }

}

CDI单元的下一个版本(2.1.1)添加了对EasyMock的支持,与当前支持Mockito的方式相同。

为什么不在测试中创建模拟,并使用
新的ResultYearMServiceImpl(stockDao)
创建要测试的对象?这就是依赖项注入的全部要点:能够在单元测试中手动注入模拟依赖项。单元测试类不需要CDI,我不使用CDI进行单元测试,我使用CDI进行整个项目。当应用程序运行时,CDI在许多类中注入ResultYearMServiceImpl本身。所以我需要为单元测试保留cdi,而不需要修改我的构造函数以满足单元测试的需要,因为您正在使用依赖项注入。所以注入你的依赖。您可以使用构造函数、setter或reflaction技巧来访问注入的字段。如果您的模拟框架不支持这些反射技巧,那么使用字段注入不是明智的选择。Mockito支持使用注释进行字段注入。EasyMock可以很好地使用Spring(我在另一个项目中使用它),因此为了避免每个项目都进行更改,我更喜欢使用相同的框架。我知道Mockito是这样做的,但我的问题是:EasyMock是否可能?是的,我也找到了这个解决方案,但我认为这是一个非常肮脏的解决方案。在这里,类只有一个mock,因此需要创建一个变量(myMock)。在一个非常大的项目中,当你有50/60需要创建时,你会怎么做?你创建了50个变量吗?这个解决方案对于解决小项目的问题很好,但对于大项目就不行了。我同意并认为最糟糕的部分是必须编写生产者方法。在大型项目中,您仍然需要编写数百个制作人,每个模拟类型一个制作人。因此,希望easymock CDI扩展很快发布。我找到了这一个,但它不是很更新。我在EasyMock的JIRA中创建了一个新的功能请求:。如果你同意,请投票。
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);
}
}
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;
    }

}