如何模拟EntityManager [英] How to mock EntityManager

查看:82
本文介绍了如何模拟EntityManager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我首先在这里发布了有关单元测试,EntityManager和NullPointerException 的问题.然后有人建议我抬头嘲笑,所以我照做了.但是,我仍然面临着同样的问题.我想知道我是否想念什么?是否有我忘记添加的设置?我需要指出持久性XML文件的位置吗?我会为此提供任何帮助.

I first posted a question on here about a Unit test, EntityManager and NullPointerException. And then somebody advised me to look up mocking, so I did. However, I am still facing the same issues. I like to know if I am missing something? Is there a setup I forgot to add? Do I require to indicate the location of the persistence XML file? I would appreciate any help with that.

我看了其他类似的问题.但是,我运气不好.

I looked at other similar questions. However, I didn’t have much luck.

1./如何在EntityManager中模拟对象?

2./如何模拟EntityManager?

3./模拟EntityManager

package com.beetlehand.model.dao;

import com.beetlehand.model.AttributeEntity;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

public class AttributeDaoTest {

    public AttributeEntity entity = new AttributeEntity();
    
    private AutoCloseable closeable;

    @Mock
    private EntityManager entityManager;

    @Test
    void testGetById(){

        TypedQuery<AttributeEntity> queryByMock =  (TypedQuery<AttributeEntity>) Mockito.mock(TypedQuery.class);
        Mockito.when(entityManager.createQuery("SELECT a FROM attributes a WHERE attribute_id = 1"))
                .thenReturn(queryByMock);
        Mockito.when(queryByMock.getSingleResult()).thenReturn(entity);

    }

    @BeforeEach
    void setUp() {

        closeable = MockitoAnnotations.openMocks(this);

    }

    @AfterEach
    void tearDown() throws Exception{

        closeable.close();

    }

}

持久性配置文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">

    <persistence-unit name="NewPersistenceUnit">
        <class>com.beetlehand.model.AttributeEntity</class>
        <class>com.beetlehand.model.AttributeValueEntity</class>
        <class>com.beetlehand.model.AuditEntity</class>
        <class>com.beetlehand.model.CategoryEntity</class>
        <class>com.beetlehand.model.CustomerEntity</class>
        <class>com.beetlehand.model.DepartmentEntity</class>
        <class>com.beetlehand.model.OrderDetailEntity</class>
        <class>com.beetlehand.model.OrdersEntity</class>
        <class>com.beetlehand.model.ProductEntity</class>
        <class>com.beetlehand.model.ProductAttributeEntity</class>
        <class>com.beetlehand.model.ProductCategoryEntity</class>
        <class>com.beetlehand.model.ReviewEntity</class>
        <class>com.beetlehand.model.ShippingEntity</class>
        <class>com.beetlehand.model.ShippingRegionEntity</class>
        <class>com.beetlehand.model.ShoppingCartEntity</class>
        <class>com.beetlehand.model.TaxEntity</class>
        <properties>
            <property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/beetlehand"/>
            <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/beetlehand"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="openjpa.ConnectionURL" value="jdbc:mysql://localhost:3306/beetlehand"/>
            <property name="openjpa.ConnectionDriverName" value="com.mysql.jdbc.Driver"/>
            <property name="eclipselink.jdbc.url" value="jdbc:mysql://localhost:3306/beetlehand"/>
            <property name="eclipselink.jdbc.driver" value="com.mysql.jdbc.Driver"/>

            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/beetlehand"/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="toor" />

        </properties>
    </persistence-unit>
</persistence>

推荐答案

那个某人"可能是我,所以我试图澄清我可能不清楚的评论.

正如评论所建议的那样,您可能不想模拟EntityManager.我认为有可能这样做,但毫无意义.现在,问题很可能是您需要澄清什么是 单元 和什么 集成 测试以及何时进行.要做那个.

As the comment suggests you might not want to mock EntityManager. It is possible I think but there is no point to do that. The issue now is more likely that you need to clarify yourself about what is unit and what integration test and when to do which.

我尝试澄清一下.

您有一个查询:

SELECT a FROM attributes a WHERE attribute_id = 1;

您如何测试查询的格式正确,并返回您想要的内容?您可能会打开db shell并运行一些查询以查看它是否有效,但是要在Java中使用它,作为回归测试,除了创建集成测试以外,没有其他方法可以将一些测试数据插入到您要查询的db中.然后应用此查询.

How do you test that query is well formed and it returns what you want? You might open db shell and run some queries to see it works but to have it in Java and as regression test there is no other way than create an integration test that inserts some test data to db to which you then apply this query.

因此,无需嘲笑EntityManager,因为您需要真实的.这就要求测试环境/框架能够注入真正的EntityManager(我五年前曾经使用Arquillian,但猜测还不止于此).

So no mocking of EntityManager because you need the real one. That requires test environment/framework that is capable to inject this real EntityManager (I used to use Arquillian some five years ago but guess there are more than that).

您可能已经明智地设计了DAO,并且拥有类似这样的类:

You might have designed your DAO wisely and have a class like:

@LocalBean // not necessarily a local bean but something that declares it as a bean
public class MyDao {
    
    @Resource
    private EntityManager em;

    public AttributeEntity getByAttributeId(Long id) {
        // return the AttributEntity found by the query you now have
    }
}

然后您将进行集成测试,其外观类似于:

Then you would have integration test that looks something like:

public class MyDaoIT {
    
    @Resource 
    // EntityManager is in your MyDao and you should no more be interested 
    // about it in your test
    private MyDao myDao;

    public AttributeEntity testGetByAttributeId1() {
        // just as an example
        assertEquals(1L, myDao().getByAttributeId(1).getAttributeId());
    }
}

上述-再次-需要一些测试框架来初始化测试容器.

The above -again- needs some test framework which initializes a test container.

但是无论如何,这与嘲笑有什么关系?如果没有必要使模拟真实",则模拟也可以与集成测试一起使用.某些对象的初始化,但EntityManager并非如此.

But what does this have to do with mocking anyway? Mocking can be used used also with integration tests if there is no point to make "real" initialization for some object but EntityManager is not the case.

您可能会说-模拟是将模拟应用于您不想初始化和/或测试但您的代码需要它的东西.通常,单元测试就是这种情况,例如,您不想等待20秒就可以使测试容器初始化为运行1ms测试并使冗余测试再次成为真实数据库.

You could say - as some kind a rule of thumb - that mocking is applied to stuff you do not want to initialize and/or test but your code needs it. And Usually this is the case with unit tests where you do not want to wait 20 seconds to get test container initialize to run 1ms test and make redundant tests agains a real database, for example.

您还可以具有一些使用MyDao的服务类,并且该类具有要测试的一些业务逻辑:

You also could have some service class that uses MyDao and which has some business logic you want to test:

public class MyService {
    @Resource
    private MyDao myDao;

    // just some very bad example method
    public AttributeEntity getCopyOfAttributeEntity(Long id) {
        AttributeEntity ae = myDao.getByAttributeId(id);
        AttributeEntity aeCopy = ae.clone(); // suppose clone works ;)
        aeCopy.setAttributeId(ae.getAttributeId() + 1);
    }
}

您要在这里测试什么?因为您已经在集成测试中对其进行了测试,所以不是该查询,对吗?在这里,您要模拟MyDao并测试服务中的业务逻辑.如此生成的测试类如下:

What do you want to test here? Not the query since you already tested it in your integration test, right? Here you want to mock your MyDao and test the business logic in your service. So resulting test class like:

public class MyServiceTest {
    @Mock
    private MyDao myDao;
    @InjectMocks
    private MyService myService;

    public AttributeEntity testGetCopyOfAttributeEntity1() {
        // The part where mock stuff is initialized
        AttributeEntity ae = new AttributeEntity();
        ae.setAttributeId(1L);
        doReturn(ae).when(myDao).getByAttributeId(1L);
        // The part you test the logic in your service
        AttributeEntity aeCopy = myService.getCopyOfAttributeEntity(1L);
        assertEquals(2, aeCopy.getAttributeId());
    }
}

这篇关于如何模拟EntityManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆