Java 中删除方法的单元测试?

Unit Test for delete method in Java?

我正在尝试通过单元测试来测试以下方法:

@Override
@Transactional
public void delete(UUID uuid) {
    final Company company = companyRepository.findByUuid(uuid)
            .orElseThrow(() -> new EntityNotFoundException(COMPANY_NAME));

    deletionService.delete(company);
    companyRepository.save(company);
}

这里是 DeletionService 实现:

@Override
public void delete(final DeletableEntity deletableEntity) {
    deletableEntity.setDeleted(true);
    deletableEntity.setDeleteDate(Instant.ofEpochMilli(clock.millis()));
    deletableEntity.setDeletedByUserUuid(currentUser.getUuid());
}

我创建了以下测试方法:

@Test(expected = EntityNotFoundException.class)
public void test_Delete() {
    final UUID uuid = UUID.randomUUID();
    final String name = "Company";
    final Company company = new Company(name);

    when(companyRepository.findByUuid(uuid)).thenReturn(Optional.of(company));

    companyService.delete(uuid);

    // I think this returns company instead of EntityNotFoundException 
    // due to the condition in "Mockito.when(...)"
    companyRepository.findByUuid(uuid);
}

调试器命中直到 companyRepository.findByUuid(uuid); 行没有任何问题,但执行该行不会抛出错误。我认为这是由于“Mockito.when(...)”中的条件所致。那么,我应该如何修改此测试以便测试我的 soft delete 方法?

这是我的 Company 实体,它从 DeletableEntity:

延伸而来
//some annotation here
public class Company extends DeletableEntity  {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "company_gen")
    private long id;

    @Column(nullable = false)
    private String name;

    public Company(@Nonnull String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object other) {
        return super.equals(other);
    }
}
@MappedSuperclass
public class DeletableEntity extends BaseEntity {

    private boolean deleted;

    private Instant deleteDate;

    private UUID deletedByUserUuid;
}

更新: 这是我编辑的方法的最后状态:

@Test
public void test_Successful_Delete() {
    // Arrange
    final String name = "Company";
    final Company company = new Company(name);

    when(companyRepository.findByUuid(company.getUuid()))
        .thenReturn(Optional.of(company));
    doNothing().when(deletionService).delete(isA(Company.class));
    when(companyRepository.save(isA(Company.class))).thenReturn(company);

    // Act
    companyService.delete(company.getUuid());

    // Assert
    verify(deletionService, times(1)).delete(isA(Company.class));
    verify(companyRepository, times(1)).save(isA(Company.class));
}
@Test(expected = EntityNotFoundException.class)
public void test_Delete_thenThrowException() {
    final String name = "Company";
    final Company company = new Company(name);

    when(companyRepository.findByUuid(company.getUuid())).thenReturn(Optional.empty());

    companyService.delete(company.getUuid());
}

如果你想测试这样的方法,你必须通过两个测试来完成:

  1. 如果 companyRepository.findByUuid() returns 任何东西,测试 companyRepository.save() 确实被调用;
  2. 测试该方法在 companyRepository.findByUuid() returns 什么都没有时抛出 EntityNotFoundException

1. 类似于以下内容:

@Test
public void test_Successful_Delete() {
    // Arrange
    final UUID uuid = UUID.randomUUID();
    final String name = "Company";
    final Company company = new Company(name);
    when(companyRepository.findByUuid(uuid)).thenReturn(Optional.of(company));
    when(deletionService.delete(isA(Company.class))).thenReturn(true; // I am assuming deletionService.delete() returns a boolean, if that is not the case you will need to adjust this
    when(companyRepository.save(isA(Company.class))).thenReturn(true; // I am assuming companyRepository.save() returns a boolean, if that is not the case you will need to adjust this

    // Act
    companyService.delete(uuid);

    // Assert
    verify(deletionService, times(1)).delete(isA(Company.class));
    verify(companyRepository, times(1)).save(isA(Company.class));
}

2. 看起来如下(与您的相似):

@Test
public void test_Unsuccessful_Delete() {
    // Arrange
    final UUID uuid = UUID.randomUUID();
    final String name = "Company";
    final Company company = new Company(name);
    when(companyRepository.findByUuid(uuid)).thenReturn(Optional.empty());

    try {
      // Act
      companyService.delete(uuid);
      Assert.fail("Exception not thrown");
    } catch (EntityNotFoundException e) {
      // Assert
      verify(deletionService, never()).delete(isA(Company.class));
      verify(companyRepository, never()).save(isA(Company.class));
    }
}

P.S.: assertThat 是一个 AssertJ 方法 (org.assertj.core.api.Assertions.assertThat).