使用Spring Security的Principal的单元测试方法



有人能告诉我应该如何测试这两种方法吗:

public boolean deleteUser(Principal principal) {
if (findLoggedInUser(principal) != null) {
userRepository.delete(findLoggedInUser(principal));
return true;
}
return false;
}
public User findLoggedInUser(Principal principal) {
return findUserbyUsername(principal.getName());
}

问题是,我使用的是具有基本身份验证的当前登录用户,不知道如何使用,也不知道我是否可以嘲笑这些Principals。有办法做到这一点吗?这些方法在我的服务层中,所以也许我不能进行单元测试,而我只能进行集成测试,因为这些方法大量使用DB?

编辑1:我更改的测试类:

public class UserServiceBeanTest {
@Spy
@InjectMocks
private UserServiceBean userServiceBean;
@Mock
private UserRepository userRepository;
@Mock
private Principal principal;
@Mock
private PasswordEncoder passwordEncoder;
@Mock
private User userStub;
private String defaultName = "user";
private  String defaultPassword = "password";
private String defaultEmail = "example@example.com";
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}

@Test
public void shouldReturnTrue_whenUserDeleted() {
//given
when(principal.getName()).thenReturn(defaultName);
when(userServiceBean.findLoggedInUser(principal)).thenReturn(userStub);
// when
boolean removed = userServiceBean.deleteUser(principal);
//then
assertTrue(removed);
verify(userRepository, times(1));
}
@Test
public void shouldReturnFalse_whenUserNotFound() {
//given
when(principal.getName()).thenReturn(defaultName);
when(userServiceBean.findLoggedInUser(principal)).thenReturn(null);
//when
boolean removed = userServiceBean.deleteUser(principal);
//then
assertFalse(removed);
verify(userRepository, times(0));
}
}

我现在收到这些错误:

org.mockito.exceptions.misusing.UnfinishedVerificationException: 

导弹

g method call for verify(mock) here:
-> at com.doublemc.services.UserServiceBeanTest.shouldReturnTrue_whenUserDeleted(UserServiceBeanTest.java:63)
Example of correct verification:
verify(mock).doSomething()
Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.

at com.doublemc.services.UserServiceBeanTest.init(UserServiceBeanTest.java:48)

编辑2:这是我的UserServiceBean类:

package com.doublemc.services;
import com.doublemc.domain.ToDoItem;
import com.doublemc.domain.User;
import com.doublemc.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.security.Principal;
@Service
@Transactional
public class UserServiceBean {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Autowired
UserServiceBean(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public User saveUser(User user) {
User newUser = new User();
newUser.setUsername(user.getUsername());
newUser.setEmail(user.getEmail());
newUser.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(newUser);
}
public boolean userExists(User user) {
return userRepository.findByUsername(user.getUsername()) != null;
}
public Iterable<ToDoItem> getAllToDoItems(User user) {
return user.getToDoItems();
}
public boolean deleteUser(Principal principal) {
if (findLoggedInUser(principal) != null) {
userRepository.delete(findLoggedInUser(principal));
return true;
}
return false;
}
public User findLoggedInUser(Principal principal) {
return userRepository.findByUsername(principal.getName());
}

}

这是我的UserRepository:

public interface UserRepository extends CrudRepository<User, Long> {
User findByUsername(String username);
}

编辑6:我为自己创建了另外三个测试:

@Test
public void shouldReturnUser_whenPassedUser() {
// given
when(userRepository.save(any(User.class))).thenReturn(new User(defaultName, defaultPassword, defaultEmail));
// when
User savedUser = userServiceBean.saveUser(userStub);
// then
assertNotNull(savedUser);
verify(userRepository, times(1)).save(any(User.class));
}
@Test
public void shouldReturnTrue_whenUserExists() {
// given
when(userStub.getUsername()).thenReturn(defaultName);
when(userRepository.findByUsername(userStub.getUsername())).thenReturn(userStub);
// when
boolean exists = userServiceBean.userExists(userStub);
// then
assertTrue(exists);
verify(userRepository, times(1)).findByUsername(defaultName);
}
@Test
public void shouldReturnFalse_whenUserNotFoundByUsername() {
// given
when(userStub.getUsername()).thenReturn(defaultName);
when(userRepository.findByUsername(userStub.getUsername())).thenReturn(null);
// when
boolean exists = userServiceBean.userExists(userStub);
// then
assertFalse(exists);
verify(userRepository, times(1)).findByUsername(defaultName);
}

以下是经过测试的方法:UserServiceBean.saveUser:

public User saveUser(User user) {
User newUser = new User(user.getUsername(), user.getEmail(), passwordEncoder.encode(user.getPassword()));
return userRepository.save(newUser);
}

UserServiceBean.userExists:

public boolean userExists(User user) {
return userRepository.findByUsername(user.getUsername()) != null;
}

我就是这样做的(Junit+Mockito)。

在给定的例子中有两个测试用例。

Btw。。我想你可以做一点重构,因为你(我想)打了两次数据库:

public boolean deleteUser(Principal principal) {
User loggedUser = findLoggedInUser(principal);
if (loggedUser != null) {
userRepository.delete(loggedUser);
return true;
}
return false;
}

测试。。

import static org.mockito.Mockito.*;
import mypkg.Service;
import mypkg.User;
import mypkg.UserRepository;
import org.junit.Assert;
import org.junit.Before;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import java.security.Principal;
public class ServiceTest {
@Spy
@InjectMocks
private Service service;
@Mock
private UserRepository userRepository;
@Mock
private Principal principal;
@Mock
private User userStub;
private String defaultName = "name";
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
@org.junit.Test
public void shouldReturnTrue_whenUserDeleted() throws Exception{
// Arrange
when(principal.getName()).thenReturn(defaultName);
when(service.findUserbyUsername(defaultName)).thenReturn(userStub);
// Act
boolean removed = service.deleteUser(principal);
// Assert
Assert.assertTrue(removed);
verify(userRepository, times(1)).delete(userStub);
}
@org.junit.Test
public void shouldReturnFalse_whenUserNotFound() throws Exception{
// Arrange
when(principal.getName()).thenReturn(defaultName);
when(service.findUserbyUsername(defaultName)).thenReturn(null);
// Act
boolean removed = service.deleteUser(principal);
// Assert
Assert.assertFalse(removed);
verify(userRepository, times(0)).delete(userStub);
}
}

从中获得的最大好处是,您可以Mock/Stub任何外部依赖项(在本例中为UserRepository),并只关注该服务方法中包含的逻辑。delete内部的内容与测试无关。。您所关心的只是该方法是否已被某个参数调用。。就是这样。

如果一切都清楚了,请告诉我。。如果需要,我会解释的。

更新

@InjectMocks是一种将依赖项注入要测试的类的方便方法。注入通过setter/constructor进行,或者作为最后手段通过反射进行。

在上面的例子中,由于Service类具有UserRepository依赖项,并且有一个@Mock定义:

@Mock
private UserRepository userRepository;

Mockito将把它注入Service

@Spy类似于@Mock,只是它允许您选择性地仅模拟某些bahvio,并且在默认情况下调用实际实现。

在我的例子中,我用它来模拟ServicefindUserbyUsername方法,因为在我们的两个测试中,内部的内容并不重要:

when(service.findUserbyUsername(defaultName)).thenReturn(userStub);

最新更新