繁体   English   中英

在 Spring Boot 中使用模拟存储库测试 void 服务方法?

[英]Testing a void service method with mocked repository in Spring Boot?

我的 Spring 引导应用程序提供以下服务,该服务增加User实体上的计数器并将其持久化到数据库中。

@Service
public class MyService {
    
    @Autowired
    UserRepo userRepo;
    
    public void incrementLoginFailures(String email) throws UserNotFoundException {
        final User user = userRepo.findByEmail(email).orElseThrow(UserNotFoundException::new);
        user.incrementLoginFailures();
        userRepo.save(user);
    }
}

现在我想为此编写一个 JUnit 5 测试,最好是 mocking 存储库,但我想我在这里理解 mocking 的概念有些困难。

如您所见,服务方法incrementLoginFailures()不返回任何内容,因此我不知道如何检查User实体上的登录计数器是否实际增加了。 我是否需要为这种实际上启动数据库的检查编写集成测试?

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

  @InjectMocks
  private UserService userService;

  @Mock
  private UserRepo userRepo;

  @Test
  public void shouldIncrement() {
    userService.incrementLoginFailures("foo@bar.com");
    Assertions.assertEquals(1, xyz);  // from what source would xyz come from?
  }
}

在调用userService.incrementLoginFailures("foo@bar.com");之前的测试方法中您将需要模拟 userRepo 上调用的方法的返回值,如下所示:

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

  @InjectMocks
  private UserService userService;

  @Mock
  private UserRepo userRepo;

  @Test
  public void shouldIncrement() {
    User user = new User();//please initialize as per your requirement
    when(userRepo.findByEmail("foo@bar.com")).thenReturn(user);
    userService.incrementLoginFailures("foo@bar.com");//this method will make changes to the user object
    Assertions.assertEquals(1, user.getLoginFailures());
  }
}

我建议从方法中返回用户 object 以帮助测试。 要设置模拟存储库行为,请使用Mockito.when并返回新用户 POJO。 然后在返回的 object 上断言登录失败计数为 1。

您应该只测试您自己的代码,并在单元测试该单元的代码。 因此,例如,如果 Spring 数据存储库save()有效,则不是。 你可以测试它,但你应该相信它是有效的。

如果做得正确,你应该有一个单元测试断言user.incrementLoginFailures()可以正常工作。

// Unit test for the user
@Test
public void shouldIncrement() {
    User user = new User();
    // In here when you have just initialized user you might know that 
    // the initial count is zero but it is overall better to assert 
    // the logic for any value / case
    int originalLoginFailures = user.getLoginFailures();
    user.incrementLoginFailures();
    assertEquals(originalLoginFailures + 1, user.getLoginFailures());
 }

除了将数据保存到数据库之外,这实际上是您需要知道的。

所以你可能有一个UserService的单元测试(或者它是 MyService?),它断言userIncrementLoginFailures()userRepo.save()是为用户调用 email foo@bar.comuserService.incrementLoginFailures("foo@bar.com")被调用。

这将通过verify来完成,例如:

@InjectMocks
private MyService userService;
@Mock
private UserRepo userRepo;
@Mock
private User user; 

@Test
public void shouldIncrementAndSave() throws UserNotFoundException {
    when(userRepo.findByEmail("foo@bar.com")).thenReturn(Optional.of(user));
    userService.incrementLoginFailures("foo@bar.com");
    verify(user).incrementLoginFailures();
    verify(userRepo).save(user);
}

您可以测试user.incrementLoginFailures()也可以在这里工作,但是因为您在用户单元测试中对其进行了测试,所以不一定需要它,而是一个冗余测试,并测试不属于单元测试的逻辑,即UserService

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM