【问题标题】:Junit: writing a test for a method that deletes an entity?Junit:为删除实体的方法编写测试?
【发布时间】:2016-10-31 02:23:44
【问题描述】:

我可以为以下代码编写的最详尽测试是什么?

public void deleteFromPerson(person person) {
    person = personRepository.returnPerson(person.getId());
    personRepository.delete(person);
}

此方法在a service 类中。该方法调用JpaRepository,然后在实体上调用它的delete() 方法。

如果无法测试实体是否被删除,是否有任何其他tests cases我可以在该方法上运行?

【问题讨论】:

  • 您可以通过检索 person 对象来测试这一点,确保它被成功检索,然后删除它并再次尝试检索它。如果第二次无法找回,则删除成功。
  • 如果无法测试实体是否被删除 如果你正在编写单元测试,测试的职责是确保personRepository.delete方法被称为,而不是它实际上有效。如果您正在编写集成测试,您应该创建一个Person,验证其存在,然后将其删除并验证其不存在。
  • 同时测试删除无效 id 或有效 id 两次是否如您所愿。
  • 你可以测试甚至调用监听器。您可以测试该对象不再在数据库中(在检查之前从 L1/L2 缓存中逐出所有对象)。
  • @Compass 你能举一个测试方法被调用的例子吗?

标签: java hibernate jpa junit spring-data


【解决方案1】:

有两种测试策略。一种是单元测试,即确保您的服务正常工作。另一个是集成/端到端测试,即确保一切都很好地结合在一起。

你对你拥有的东西进行单元测试,你对你拥有的一切进行集成测试。这是一个非常粗略的示例,仅使用您的陈述,加上一些我无法填补空白的虚构内容。

单元测试

使用 Mockito

PersonRepository personRepository = mock(PersonRepository.class);

@TestSubject
PersonService personService = new PersonService(): 

@Test
public void unitTest() {
    personService.setPersonRepository(personRepository);
    Person person = new Person(1L);
    Person person2 = new Person(1L);

    when(personRepository.returnPerson(1L)).thenReturn(person2); //expect a fetch, return a "fetched" person;

    personService.deleteFromPerson(person);

    verify(personRepository, times(1)).delete(person2); //pretty sure it is verify after call
}

使用 EasyMock...

@Mock
PersonRepository personRepository; //assuming it is autowired

@TestSubject
PersonService personService = new PersonService(): 

@Test
public void unitTest() {
    Person person = new Person(1L);
    Person person2 = new Person(1L);

    EasyMock.expect(personRepository.returnPerson(1L)).andReturn(person2); //expect a fetch, return a "fetched" person;
    personRepository.delete(person2);
    EasyMock.expectLastCall(); //expect a delete for person2 we plan to delete
    replayAll();

    personService.deleteFromPerson(person);

    verifyAll(); //make sure everything was called
}

是的,这个测试看起来是死板的,但无论如何,这就是你在单元测试中测试的全部内容。您希望 DB 使用参数从数据库中获取 Person,因此有两个 Person 对象,并且您希望删除传递的 Person 对象,这就是您期望调用的原因。简单的方法产生简单的测试。您基本上希望确保您按预期与存储库进行交互。存储库在实际实现中可能会损坏或为空,但这不会改变您的服务已正确实现的事实。

集成测试

另一方面,如果您想进行集成测试,则不使用模拟。相反,您需要连接 test DB 和 repo 等所有内容。由于没有实施参考,因此由您决定。

@Test
public void integrationTestForAddAndDelete() {
    Person person = createDummyPersonForInsertion(); //static method that creates a test Person for you
    Person comparePerson;
    //make sure we haven't added the person yet
    Assert.assertNull(personService.getPerson(person));

    //add the Person
    comparePerson = personService.addPerson(person);
    Assert.assertNotNull(personService.getPerson(person));
    //add a rigorous compare method to make sure contents are the same, i.e. nothing is lost or transmuted incorrectly, ignoring ID if that is autogen
    //alternatively, you can create a unit test just for Person
    Assert.assertEquals(person, comparePerson); 

    //remove the Person
    personService.deleteFromPerson(person);
    Assert.assertNull(personService.getPerson(person));

    //test for exception handling when you try to remove a non-existent person;
    personService.deleteFromPerson(person);

    //test for exception handling when you try to remove null
    personService.deleteFromPerson(null);
}

在这种情况下,您要确保您的 repo 实际处理来自服务的所有调用。您知道您的服务在单元测试中有效,但 repo 是否在服务中有效,或者您是否配置了错误

【讨论】:

  • 感谢您提供的示例,您能否快速重写使用 Mockito 的示例,我从未使用过简单的模拟,所以我觉得它很混乱?
  • 添加了 Mockito 的粗略概念。如果您知道 Mockito,则切换到 EasyMock 的语法应该非常相似。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-02
  • 2022-01-23
  • 1970-01-01
  • 2023-02-17
  • 2019-11-01
  • 2022-11-18
相关资源
最近更新 更多