【问题标题】:Mockito DAO interface from service impl来自服务实现的 Mockito DAO 接口
【发布时间】:2018-11-18 10:24:35
【问题描述】:

我正在使用 Mockito 测试我的 API 服务 REST,我正在使用 Spring Framework 4.1.4.RELEASE 和 Mockito 1.9.5。

我有一个用于访问唯一 DAOImpl 的多品牌系统(每个品牌都是唯一的 @PersistenceContext(unitname = "emX"),其中“X”是品牌字符),每个品牌都从抽象 DaoBase 类(谁实现一个名为 Dao 的接口),我通过以下方式从 Service 类获取组件访问:

applicationContext.getBean(qualifier.concat(brand.name()), clazz)

(以 qualifier.concat(brand.name()) its = "DaoA" 为例)

这是结构:

  • es.app.service
    • ServiceClass.java 调用 DaoFactory 获取 Impl。
  • es.app.dao
    • Dao.java
    • DaoBase.java 实现 Dao
    • DaoFactory.java
  • es.app.dao.impl
    • DaoAImpl.java 扩展了 DaoBase @Repository("DaoA")
    • DaoBImpl.java 扩展了 DaoBase @Repository("DaoB")
    • DaoCImpl.java 扩展了 DaoBase @Repository("DaoC")
    • DaoDImpl.java 扩展了 DaoBase @Repository("DaoD")

然后我有一个关于测试包的测试类

  • es.app.service

    ServiceClassTest.java

我在这里为每个类放了一点代码:

DaoFactory.java

@Component
public class DaoFactory implements Serializable, ApplicationContextAware{

    private ApplicationContext  ctx;
    private static final long   serialVersionUID    = 1L;
    private static final Logger LOGGER  = LoggerFactory.getLogger(DaoFactory.class);

    public Dao getInstance(GroupBrand brand){
        switch(brand){
            case A:
            case B:
            case C:
            case D:
                return (Dao)getComponent("Dao",Dao.class, brand);
            default: break;
        }
        throw new IllegalArgumentException("Unsupported brand ".concat(brand.name()));
    }

    private Object getComponent(String qualifier, Class<?> clazz, GroupBrand brand){
        Object instance = ctx.getBean(qualifier.concat(brand.name()), clazz);
        if(Utils.isNull(instance)){
            throw new IllegalArgumentException("Unkown business bean with Qualifier:  ".concat(qualifier.concat(brand.name())).concat("type: ").concat(clazz.getName()));
        }
        LOGGER.debug("DAO retrived: " + qualifier.concat(brand.name()) +" class: " + clazz.getName());
        return instance;
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx = applicationContext;
    }


}

DaoBase.java

public abstract class DaoBase implements Dao {


    protected abstract EntityManager getEntityManager();
    private static final String EMPTY = "";
    private static final Logger     LOGGER  = LoggerFactory.getLogger(DaoBase.class);

    @Override
    public Boolean findAvailability(GroupBrand marca, String code) {
        EntityManager em = getEntityManager();
        Query query = em.createNamedQuery("Conn.isAvailability");
        query.setParameter(1, code);
        query.setParameter(2, marca.toCharCode());
        try{
            String value = (String)query.getSingleResult();
                        if(value.equalsIgnoreCase("S")){
                            return true;
                        }else{
                            return false;
                        }
        }catch(Exception ex){
            return Boolean.FALSE;
        }
    }

}

DaoAImpl.java

@Repository("DaoA")
public class DaoAImpl extends DaoBase {

    @PersistenceContext(unitName = "emA")
    private EntityManager em;

    @Override
    @Transactional("A")
    public Boolean findAvailability(GroupBrand marca, String code) {
        return super.findAvailability(marca, code);
    }
}

ServiceClass.java

    @Override
    public boolean isAvailable(GroupBrand brand, String code){
        Boolean available = getDMSQisAvailability(brand, code);
        return available;
    }

    protected Boolean isAvailability(GroupBrand marca, String kvps){
        boolean value = daoFactory.getInstance(marca).findDMSQisAvailability(marca, code);
        return value;
    }

ServiceClassTest.java

    @InjectMocks
        @Autowired
        @Qualifier("serviceClass")
        private ServiceClass srv;

    @Autowired
    @Qualifier("DaoFactory")
    protected DaoFactory daoFactory;

    @Mock
    protected Dao dao;

    @Override
    public void mockBehaivors() throws ResourceException, ResourceNotFoundException, ApiException {
        MockitoAnnotations.initMocks(this);

        dao = daoFactory.getInstance(marca);

        when(dao.findAvailability(any(GroupBrand.class), any(String.class))).thenReturn(Boolean.TRUE);

    }

    @Test
        public void isAvailableTest() throws ResourceException, Exception{
            Boolean available = srv.isAvailable(GroupBrand.A, "CODE");
        } 

我需要覆盖 ServiceClass.java 类,但我不能模拟来自这个 Test 类的 Dao 调用总是做真正的调用并且不返回我在“何时”定义的内容,其他测试工作但不使用 dao 访问。

谁能帮帮我?

(为我糟糕的英语道歉)..

问候,

【问题讨论】:

  • 你试过下面的解决方案了吗!

标签: spring mockito


【解决方案1】:

至少我找到了解决问题的方法,

当调用 getInstance() 时我必须模拟 DaoFactory 我返回 Dao 类的模拟。

像这样对它进行类测试:

@InjectMocks
@Autowired
@Qualifier("serviceClass")
private ServiceClass srv;

@Mock
@Autowired
@Qualifier("DaoA")
protected Dao dao;

@Mock
@Autowired
@Qualifier("DaoFactory")
protected DaoFactory daoFactory;

@Override
public void mockBehaivors() throws ResourceException, ResourceNotFoundException, ApiException {
    MockitoAnnotations.initMocks(this);

    when(daoFactory.getInstance(GroupBrand.A)).thenReturn(dao);

    when(dao.findAvailability(any(GroupBrand.class), any(String.class))).thenReturn(Boolean.TRUE);

}

@Test
    public void isAvailableTest() throws ResourceException, Exception{
        Boolean available = srv.isAvailable(GroupBrand.A, "CODE");
    } 

它的作品!!!!

【讨论】:

    【解决方案2】:

    尝试在 DAO 上使用 @MockBean(理想情况下 @Mock 也一样)并按照下面的说明进行存根。 在测试用例初始化方法上注释@Before,并将when子句逻辑移动到实际测试用例(我总是这样做)

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MyServiceTest extends MyServiceImpl {
    
    
    
        @Autowired
        private MyService myervice;
    
        @MockBean
        private MyDAO myDao;
    
        @Before
        public void setupMock()
        {
            MockitoAnnotations.initMocks(this);
        }
    

    您可以尝试创建存根以不调用DAO,如下面的sn-p in 测试用例。在您的示例中,您已经在测试中完成了 初始化块

         AddressDTO planContactaddressDTO = buildAddressDTO();
       //build this stub method buildAddressDTO() to return AddressDTO which your actual DAO will return
       when(myDao.saveAddress(addressBO)).thenReturn(addressDTO);
    

    【讨论】:

    • 你好,我试过了,但它不起作用,但感谢这个我找到了解决方案!
    • 酷,你做了什么修复!
    猜你喜欢
    • 2011-12-28
    • 2012-09-21
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 2015-12-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    相关资源
    最近更新 更多