这是我第一个使用TDD和JUNIT 5的项目,我在我的项目中使用了最新的Springboot。
我注意到在使用@InjectMocks注释时,当我有来自springboot的依赖项时,它们不会在测试阶段被注入。我将获得NullPointerException作为authenticationManager依赖项。但是,当服务方法只使用使用springboot JPA为实体类创建的存储库依赖时,测试就会通过。
下面是服务类和相应的测试类。UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
UserRepository userRepository;
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
UserDetailsService userDetailsService;
@Autowired
JWTUtil jwtUtil;
@Override
@Transactional
public AuthenticationResponseDTO login(AuthenticationRequestDTO authenticationRequestDTO) {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authenticationRequestDTO.getUserName(), authenticationRequestDTO.getPassword()));
UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequestDTO.getUserName());
return new AuthenticationResponseDTO(userDetails.getUsername(), jwtUtil.generateToken(userDetails));
}
catch (BadCredentialsException e) {
throw e;
}
}UserServiceImplTest.java
@InjectMocks
private UserServiceImpl userServiceImpl;
@Mock
private UserRepository userRepository;
private User userMock;
private AuthenticationRequestDTO authenticationRequestDTO;
@BeforeEach
void init(){
MockitoAnnotations.initMocks(this);
}
@BeforeEach
void setupUser(){
userMock = new User();
userMock.setUserName("sd");
userMock.setPassword("sd");
authenticationRequestDTO = new AuthenticationRequestDTO();
authenticationRequestDTO.setUserName("sd");
authenticationRequestDTO.setPassword("sd");
}
@Test
void testUserIsPresentOrNot(){
Mockito.when( userRepository.findByUserName("sd") ).thenReturn(userMock);
AuthenticationResponseDTO responseDTO = userServiceImpl.login(authenticationRequestDTO);
assertNotNull(responseDTO);
assertEquals(userMock.getUserName(), responseDTO.getName(), "user id should be same.");
}请告诉我是否需要更多的细节从我的结尾。
发布于 2020-05-12 05:13:35
我不确定我是否100%跟随,正如我所看到的一样,您缺少一些注释。
如果要在单元测试中注入Spring,则需要@SpringBootTest/@ExtendWith(SpringExtension.class) (从我的观点来看,使其成为集成测试)。
如果您想使用Mockito,@InjectMocks和@Mock需要测试类上面的@ExtendWith(MockitoExtension.class)。
并删除以下内容。
@BeforeEach
void init(){
MockitoAnnotations.initMocks(this);
}从我的观点来看,将依赖注入与spring和Mockito混合在一起太复杂了。我宁愿只使用Mockito进行单元测试。
也许下面是的文章能有所帮助。
发布于 2020-06-08 12:40:29
TL/DR
为Spring依赖项添加缺少的模拟,如下所示:
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.when;
class UserServiceImplSuite
{
public static final String USER_NAME = "USER_NAME";
public static final String PASSWORD = "PASSWORD";
@InjectMocks
private UserServiceImpl userServiceImpl;
@Mock
private UserRepository userRepository;
@Mock
private AuthenticationManager authenticationManager;
@Mock
private UserDetailsService userDetailsService;
@Mock
private JWTUtil jwtUtil;
private User userMock;
private UserDetails userDetailsMock;
private AuthenticationRequestDTO authenticationRequestDTO;
@BeforeEach
void init()
{
MockitoAnnotations.initMocks( this );
}
@BeforeEach
void setupUser()
{
userMock = new User();
userMock.setUserName( USER_NAME );
userMock.setPassword( PASSWORD );
userDetailsMock = new UserDetails();
userDetailsMock.setUsername( USER_NAME );
userDetailsMock.setPassword( PASSWORD );
authenticationRequestDTO = new AuthenticationRequestDTO();
authenticationRequestDTO.setUserName( USER_NAME );
authenticationRequestDTO.setPassword( PASSWORD );
}
@Test
void testUserIsPresentOrNot()
{
when( userRepository.findByUserName( USER_NAME ) ).thenReturn( userMock );
when( userDetailsService.loadUserByUsername( USER_NAME ) )
.thenReturn( userDetailsMock );
when( jwtUtil.generateToken( userDetailsMock ) )
.thenReturn( PASSWORD );
AuthenticationResponseDTO responseDTO = userServiceImpl.login( authenticationRequestDTO );
assertNotNull( responseDTO );
assertEquals( userMock.getUserName(), responseDTO.getName(), "user id should be same." );
}
}细目
在运行测试时,Spring不处于活动状态,除非您特别声明它使用的是注释。然而,良好的单元测试通常不需要Spring来运行。由于Spring不再管理我们的依赖项(这同样是好的),我们现在需要使用Mockito,手动地模拟和初始化它们,从而生成上面的单元测试套件。
因此,现在,每次被测试的类调用依赖项时,我们都会提供一个模拟。这将改变测试;我们不再测试“它是否生成预期值”,而是检查“它是否按顺序调用依赖项,正确地处理其结果”,这要抽象得多。
这就揭示了测试类的最大问题:过度耦合。它试图做很多很多事情,这使得我们的测试变得复杂和脆弱。减少这一点将提高生产和测试代码质量。
祝好运!
发布于 2021-09-30 09:50:14
在Junit 5中,只需使用@ExtendWith(SpringExtension.class)注释测试类以使用@InjectMocks,并确保您的导入应该来自import org.junit.jupiter.api.Test;,如下所示:
@ExtendWith(SpringExtension.class)
public class TestClass{
@InjectMocks
TestInjectMockClass testInjectMockClass;
}https://stackoverflow.com/questions/61710145
复制相似问题