如何在子类上使用Spring @DataJpaTest注解,而不是在抽象超类上使用它

pw9qyyiw  于 2023-10-20  发布在  Spring
关注(0)|答案(1)|浏览(165)

我想为我的(Spring)仓库创建一个抽象测试类,实现两次:一次使用实际的JPA存储库,一次使用内存中的假存储库。(参见https://wiki.c2.com/?AbstractTestCases
为此,我有以下设置:
一个抽象超类,需要@DataJpaTest注解

@DataJpaTest
public abstract class RepositoryTest {
    abstract TestRepo repo();
    abstract void save(Entity entity);

    @Test
    void testtest() {
       save(new Entity("ProviderId", new Date(), "event", "phase", "cat", "batch", "me" +
                "message"));

       assertThat(repo().findAll()).isNotNull();
    }
}

和一个具体的子类,它需要一些其他的Spring注解:

@ContextConfiguration(classes = TestRepo.class)
@EnableAutoConfiguration
public class JpaRepositoryTest extends RepositoryTest {
    @Autowired
    TestEntityManager em;

    @Override
    void save(Entity entity) {
        em.persist(entity);
    }

    @Override
    TestRepo repo() {
        return jpaTestRepo;
    }

}

(The内存中测试是微不足道的,保存方法只是直接保存到假仓库的内存中Map)
因为我将代码构建为端口和适配器架构,并使用Gradle模块来强制端口和适配器之间的边界,所以RepositoryTestJpaRepositoryTest位于不同的模块中。前者在域模块中,不应该依赖于Spring等任何框架。
然而,我不得不在抽象超类上添加@DataJpaTest(在域模块中),否则我会得到(令人困惑的错误):
java.lang.IllegalStateException:找不到事务EntityManager,您的测试是否在事务中运行?
有没有办法设置JpaRepositoryTest来拥有所有的Spring注解,并保持`RepositoryTest本身不受Spring的影响?

vybvopom

vybvopom1#

然而,我不得不在抽象超类上(在域模块中)添加@DataJpaTest,否则我会得到(令人困惑的错误)
你会遇到这个异常,因为你不能在没有@AutoConfigureTestEntityManager的情况下使用TestEntityManager,而@AutoConfigureTestEntityManager又是@DataJpaTest的成员(关于the issue 28067,请参见the fix):

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(DataJpaTestContextBootstrapper.class)
@ExtendWith({SpringExtension.class})
@OverrideAutoConfiguration(
  enabled = false
)
@TypeExcludeFilters({DataJpaTypeExcludeFilter.class})
@Transactional
@AutoConfigureCache
@AutoConfigureDataJpa
@AutoConfigureTestDatabase
@AutoConfigureTestEntityManager // <----
@ImportAutoConfiguration
public @interface DataJpaTest {}

如果你打算同时使用内存和真实的JPA存储库,你可以使用带有@DataJpaTest和普通抽象类的适配器:

public abstract class RepositoryTest {
    abstract TestRepo repo();
    abstract void save(Entity entity);

    @Test
    void testtest() {
       save(new Entity("ProviderId", new Date(), "event", "phase", "cat", "batch", "me" +
                "message"));

       assertThat(repo().findAll()).isNotNull();
    }
}

@DataJpaTest
public abstract class InMemoryRepositoryTestAdapter extends RepositoryTest {
}

然后,专门用于假repos的测试类从InMemoryRepositoryTestAdapter子类化,处理“真实的”JPA的测试类从RepositoryTest继承。
请注意,您不能将TestEntityManager与“真实的”JPA存储库一起使用,我将使用存储库本身进行测试设置。

相关问题