当前位置: 首页 > 面试题库 >

JPA实体必须经过单元测试,如何进行?

孔永年
2023-03-14
问题内容

我有一个Spring MVC应用程序(Spring Boot 1.2.5版),该应用程序使用JPA与流行的Sql数据库进行交互。
因此,我有几个映射数据库中所有表的实体。显然,这些类仅具有用于实体之间关系的获取器/设置器和注释。

例如:

@Entity
@Table
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonView(View.Private.class)
    private Long id;

    @Column(nullable = false)
    @JsonView(View.Public.class)
    private String name;

    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "categoryId", nullable = false, updatable = false)
    @JsonIgnore
    private Category category;

   //Constructors Getters and Setters
   ...
}

我的问题是:我应该对这些课程进行单元测试吗?我应该测试什么?怎么样


问题答案:

我建议您测试所有编写的内容(或选择编写)…因此在这种情况下,我看到以下元素:

@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "categoryId", nullable = false, updatable = false)

您可以使用此批注定义一些行为(我仅从JPA中选择行为,而JSONView批注应完成相同的操作),并且如果一切正常,就想进行单元测试(如您所定义的)。

@Test(expect = SQLException.class)
public void should_not_allow_null_name() {
    /* Given */ Article article = new Article(null, new Category());
    /* When */  articleRepository.save(article);
}

通过这种(简单的)测试,您可以遵循行为是否符合您已实现的要求。如果有人(也许是您自己)删除了此注释,您将收到警报。

但是不要测试默认行为(例如,列名,您选择让JPA(和ORM)为您选择…)所以不要测试框架,这是极限。

关于如何进行测试,我喜欢使用(自Spring
Boot起)名为DBSetup的项目。它使我可以在测试中对数据集进行硬编码,而不是冗长的XML。这是忍者小队非常有趣的项目。

测试示例:

数据库测试配置:

@Configuration
@EnableJpaRepositories(basePackages = "lan.dk.podcastserver.repository")
@EntityScan(basePackages = "lan.dk.podcastserver.entity")
public class DatabaseConfiguraitonTest {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .build();
    }

    @Bean
    @Autowired
    public FullTextEntityManager fullTextEntityManager(EntityManager entityManager) {
        return getFullTextEntityManager(entityManager);
    }

    public static final DateTimeFormatter formatter = new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral(" ").append(DateTimeFormatter.ISO_LOCAL_TIME).toFormatter();
    public static final Operation DELETE_ALL_PODCASTS = deleteAllFrom("PODCAST");
    public static final Operation DELETE_ALL_ITEMS = deleteAllFrom("ITEM");
    public static final Operation DELETE_ALL_TAGS = sequenceOf(deleteAllFrom("PODCAST_TAG"), deleteAllFrom("TAG"));
    public static final Operation DELETE_ALL = sequenceOf(DELETE_ALL_ITEMS, DELETE_ALL_TAGS, DELETE_ALL_PODCASTS, DELETE_ALL_TAGS);
}

==>
https://gist.github.com/davinkevin/bb4f62aaec031b68b8f3

并测试:

@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DatabaseConfiguraitonTest.class, HibernateJpaAutoConfiguration.class})
public class ItemRepositoryTest {

    @Autowired DataSource dataSource;
    @Autowired ItemRepository itemRepository;

    private final static DbSetupTracker dbSetupTracker = new DbSetupTracker();
    public static final Operation INSERT_REFERENCE_DATA = sequenceOf(
            insertInto("PODCAST")
                    .columns("ID", "TITLE", "URL", "TYPE", "HAS_TO_BE_DELETED")
                    .values(1, "AppLoad", null, "RSS", false)
                    .values(2, "Geek Inc HD", "http://fake.url.com/rss", "YOUTUBE", true)
                    .build(),
            insertInto("ITEM")
                    .columns("ID", "TITLE", "URL", "PODCAST_ID", "STATUS", "PUBDATE", "DOWNLOADDDATE")
                    .values(1L, "Appload 1", "http://fakeurl.com/appload.1.mp3", 1, Status.FINISH, now().minusDays(15).format(formatter), now().minusDays(15).format(formatter))
                    .values(2L, "Appload 2", "http://fakeurl.com/appload.2.mp3", 1, null, now().minusDays(30).format(formatter), null)
                    .values(3L, "Appload 3", "http://fakeurl.com/appload.3.mp3", 1, Status.NOT_DOWNLOADED, now().format(formatter), null)
                    .values(4L, "Geek INC 123", "http://fakeurl.com/geekinc.123.mp3", 2, Status.DELETED, now().minusYears(1).format(formatter), now().format(formatter))
                    .values(5L, "Geek INC 124", "http://fakeurl.com/geekinc.124.mp3", 2, Status.FINISH, now().minusDays(15).format(formatter), now().minusDays(15).format(formatter))
                    .build(),
            insertInto("TAG")
                    .columns("ID", "NAME")
                    .values(1L, "French Spin")
                    .values(2L, "Studio Knowhere")
                    .build(),
            insertInto("PODCAST_TAG")
                    .columns("PODCAST_ID", "TAG_ID")
                    .values(1, 1)
                    .values(2, 2)
                    .build()
    );

    @Before
    public void prepare() throws Exception {
        Operation operation = sequenceOf(DELETE_ALL, INSERT_REFERENCE_DATA);
        DbSetup dbSetup = new DbSetup(new DataSourceDestination(dataSource), operation);

        dbSetupTracker.launchIfNecessary(dbSetup);
    }

    @Test
    public void should_find_by_podcast_and_page() {
        /* Given */
        dbSetupTracker.skipNextLaunch();
        Integer podcastId = 1;
        PageRequest pageRequest = new PageRequest(1, 1, Sort.Direction.ASC, "id");

        /* When */
        Page<Item> itemByPodcast = itemRepository.findByPodcast(podcastId, pageRequest);

        /* Then */
        PageAssert
                .assertThat(itemByPodcast)
                .hasSize(1)
                .hasTotalElements(3)
                .hasTotalPages(3)
                .hasNumberOfElements(1);

        ItemAssert
                .assertThat(itemByPodcast.getContent().get(0))
                .hasTitle("Appload 2");
    }

==>
https://gist.github.com/davinkevin/df041729608dc21bf7f3



 类似资料:
  • 单元测试,对独立的代码功能片段,由编写代码的团队进行测试,也是一种编码,而非与之不同的一些事情。设计代码的一部分就是设计它该如何被测试。你应该写一个测试计划,即使它只是一句话。有时候测试很简单:“这个按钮看起来好吗?”,有时候它很复杂:“这个匹配算法可以精确地返回正确的匹配结果?”。 无论任何可能的时候,使用断言检查以及测试驱动。这不仅能尽早发现 bug,而且在之后也很有用,让你在其他方面担心的谜

  • 我使用JPA和Hibernate作为JPA提供程序来连接到我的数据库。我在数据库中有一个名为的表,这是我的JPA实体。 这是我代码中的一个随机JPA查询。 然后hibernate生成了sql作为 这意味着实体不作为候选者查询(复数)。明确指定后,问题就解决了。JPA或Hibernate不会自动查询复数名吗?例如,如果实体名是User,它不会在数据库中查找users表吗?我想会的,我缺少一些配置。

  • 问题内容: 如何在单元测试中测试 hashCode()函数? 问题答案: 每当我覆盖equals和hash代码时,我都会按照Joshua Bloch在“ Effective Java”第3章中的建议编写单元测试。我确保equals和hash代码是自反的,对称的和可传递的。我还确保“不等于”对所有数据成员均正常工作。 当我检查对equals的调用时,我还要确保hashCode的行为符合预期。像这样:

  • 问题内容: 我一直在学习AngularJS,并且在单元测试方面进展非常顺利,但是我遇到了一个棘手的问题。 假设我有一个简单的表格,例如: 如果我正在测试类似控制器的东西,我知道我会这样写(使用Jasmine + Karma): 但是我不知道我需要注入哪些服务,也没有运气在指南或文档中找到有关单元测试的文档。 一个单元如何在Angular中测试表单? 问题答案: 我不认为这是对此类内容进行单元测试的

  • 我昨天问了一个包括这个的问题,但它似乎是一个独立的问题。我已经坐下来开始实现一个服务类,我将使用该服务类从控制器中抽象业务逻辑,并使用EF6映射到特定的模型和数据交互。 问题是我自己已经遇到了障碍,因为我不想在存储库中抽象EF(它仍然可以在服务之外用于特定的查询等),并且希望测试我的服务(将使用EF上下文)。 我想问题是这样做有意义吗?如果是这样,那么在IQueryable引起的泄漏抽象和Ladi

  • 本文向大家介绍对Angular.js Controller如何进行单元测试,包括了对Angular.js Controller如何进行单元测试的使用技巧和注意事项,需要的朋友参考一下 一、写个简单的Angular App 在开始写测试之前,我们先写一个简单的计算App,它会计算两个数字之和。 代码如下: 二、简单说说里面涉及的一些基本概念: 创建一个 module 什么是angular.modul