【问题标题】:JUnit life-cycleJUnit 生命周期
【发布时间】:2012-06-03 04:23:36
【问题描述】:

我在使用 JUnit 做一些测试套件时遇到了生命周期问题。

为了编写方便的 JPA 2.0 单元测试 作为一名 Java 开发人员 我想:

  • 在所有测试套件之前初始化一次 EntityManagerFactory 实例。我通过使用@BeforeClass 注释来实现对象
  • 实例化一个 EntityManager 实例并在每个测试用例之前启动一个新事务,并在通知之前/之后或围绕通知回滚已启动的事务(如 AOP)
  • 能够在任何派生的测试套件之前/之后进行任何设置/拆卸操作

我一直在编写 JUnit 测试。但在这种情况下,我对列表中的第二项和第三项有疑问。

请查看以下测试套件示例:

一个抽象的测试套件

public abstract class AbstractPersistenceTest {

    protected static EntityManagerFactory emf;
    protected EntityManager em;

    @BeforeClass
    public static void setUpClass() {
        emf = Persistence.createEntityManagerFactory("test");
    }

    @Before
    public void setUp() {
        em = emf.createEntityManager();
        em.getTransaction().begin();
    }

    @After
    public void tearDown() {
        em.getTransaction().rollback();
        em.close();
    }

    @AfterClass
    public static void tearDownClass() {
        emf.close();
    }

}

派生的测试套件

public class EmployeeJpqlTest extends AbstractPersistenceTest {

    private Employee john;
    private Employee jack;

    @Before
    public void setUp() {
        john = new Employee("John Doe", 1000);
        jack = new Employee("Jack Line", 1010);

        em.persist(john);
        em.persist(jack);
    }

    @Test
    public void itShouldRetrieveAllEmplloyees() {
        TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e",
                Employee.class);
        List<Employee> employees = query.getResultList();

        assertArrayEquals(new Employee[] { john, jack }, employees.toArray());
    }

    @Test
    public void itShoulRetrieveAllEmployeeNames() {
        TypedQuery<String> query = em.createQuery(
                "SELECT e.name FROM Employee e", String.class);
        List<String> names = query.getResultList();

        assertArrayEquals(new String[] { john.getName(), jack.getName() },
                names.toArray());
    }

}

由于未指定 JUnit 生命周期注释的顺序,NullPointerException 在派生类的 setUp() 方法中占有一席之地。这对我来说很清楚。

是否可以在不手动在任何派生测试套件类的每个 setUp()/tearDown() 方法中注入启动/回滚事务代码的情况下实现目标? 或者,是否有替代的 JUnit 均值或测试框架可以提供一种简单的方式来表达我的需求?

提前致谢。

【问题讨论】:

    标签: java testing junit


    【解决方案1】:

    您对使用Google Guice 将实体管理器和事务注入您的测试方法的想法有何看法?

    import com.google.inject.persist.Transactional;
    import javax.persistence.EntityManager; 
    
    public class MyTest {
            @Inject EntityManager em; 
    
            @Test
            @Transactional 
            public void createNewPerson() {
                    em.persist(new Person(...)); 
            } 
    }
    

    它可以简化这方面的大量工作。

    【讨论】:

    • 是的,这是个好主意。由于 Google Guice 是一种精益 IoC,因此可以在不受代码影响的情况下使用它。
    【解决方案2】:

    为什么不在setUpsuper.setUpClass 等中调用super.setUp()?你实际上在做的是覆盖子类的方法。

    【讨论】:

    • 实际上我就是这样做的,因此在测试运行期间父 setUp() 方法被连续调用两次 - 一次直接来自我的代码,第二次由 JUnit 关于 JUnit生命周期。
    【解决方案3】:

    考虑使用 Spring 处理非静态实体管理器的一次性实例化和事务回滚。即使您没有在应用程序中使用 Spring,您也可以从仅在测试中使用它中受益。有关详细信息,请参阅http://static.springsource.org/spring/docs/3.0.5.RELEASE/reference/testing.html 的第 9.3 节。

    【讨论】:

    • 是的,我完全同意你的看法。这是一个非常方便的选择。那个特定的项目是如此的小而简单,所以我避免使用 Spring,了解我拒绝的内容。谢谢。
    猜你喜欢
    • 2011-12-06
    • 2019-05-08
    • 2013-04-06
    • 1970-01-01
    • 2014-09-10
    • 2021-09-14
    • 2012-02-10
    • 1970-01-01
    相关资源
    最近更新 更多