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

huangapple go评论79阅读模式
英文:

How to have Spring @DataJpaTest annotation on subclass instead of having it be required on the abstract superclass

问题

I want to create an abstract test class for my (Spring) repositories, to be implemented twice: once using the actual JPA repository, once using an in-memory fake.

For this I have the following setup:

An abstract superclass, which requires the @DataJpaTest annotation

@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();
    }
}

and a concrete subclass, which requires some other Spring annotations:

@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 in-memory test is trivial, the save method just saves to the fake repo's in-memory map directly)

Because I'm structuring my code as a ports & adapters architecture, and using Gradle modules to enforce the boundaries between the ports & adapters, the RepositoryTest and the JpaRepositoryTest are in different modules. The former is in the domain module, which should not depend on any framework such as Spring.

I am, however, forced to add the @DataJpaTest on the abstract superclass (in the domain module) or otherwise, I get the (confusing error):

java.lang.IllegalStateException: No transactional EntityManager found, is your test running in a transaction?

Is there any way to set up the JpaRepositoryTest to have all the Spring annotations and keep the RepositoryTest itself free from Spring?

英文:

I want to create an abstract test class for my (Spring) repositories, to be implemented twice: once using the actual JPA repository, once using an in memory fake. (See https://wiki.c2.com/?AbstractTestCases)

For this I have the following setup:

An abstract superclass, which requires the @DataJpaTest annotation

@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();
    }
}

and a concrete subclass, which requires some other Spring annotations:

@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 in-memory test is trivial, the save method just saves to the fake repo's in-memory map directly)

Because I'm structuring my code as a ports & adapters architecture, and using Gradle modules to enforce the boundaries between the ports & adapters, the RepositoryTest and the JpaRepositoryTest are in different modules. The former is in the domain module, which should not depend on any framework such as Spring.

I am however forced to add the @DataJpaTest on the abstract superclass (in the domain module) or otherwise I get the (confusing error):
> java.lang.IllegalStateException: No transactional EntityManager found, is your test running in a transaction?

Is there any way to setup the JpaRepositoryTest to have all the Spring annotations, and keep the `RepositoryTest itself free from Spring?

答案1

得分: 1

我被迫在抽象超类(在领域模块中)上添加@DataJpaTest注解,否则会出现(令人困惑的错误)。

出现异常的原因是您不能在没有@AutoConfigureTestEntityManager注解的情况下使用TestEntityManager,而@AutoConfigureTestEntityManager又是@DataJpaTest的一部分(请参阅问题28067的修复):

如果您打算同时使用内存和真实的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", "message"));

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

@DataJpaTest
public abstract class InMemoryRepositoryTestAdapter extends RepositoryTest {
}

然后,专用于虚假存储库的测试类是从InMemoryRepositoryTestAdapter子类继承的,而与“真实”JPA有关的测试类则是从RepositoryTest继承的。

请注意,您不能在“真实”的JPA存储库中使用TestEntityManager,我建议在测试设置中使用存储库本身。

英文:

> I am however forced to add the @DataJpaTest on the abstract superclass (in the domain module) or otherwise I get the (confusing error)

You face the exception because you cannot use TestEntityManager without @AutoConfigureTestEntityManager, which is in turn a member of @DataJpaTest (see the fix for the issue 28067):

@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 {}

If your intention is to use both in-memory and real JPA repos you could use adapter bearing @DataJpaTest and plain abstract class:

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

The test classes dedicated for fake repos are then sub-classed from InMemoryRepositoryTestAdapter and the ones dealing with "real" JPA are inherited from RepositoryTest.

Pay attention, that you cannot use TestEntityManager with "real" JPA repositories and I'd use the repos themselves for test set-up.

huangapple
  • 本文由 发表于 2023年7月4日 20:02:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76612423.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定