我有Spring接口UserDetailsService
的实现:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
@Autowired
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final UserEntity user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("Cannot find user with username " + username);
}
return new User(user);
}
}
UserRepository
是标准接口ExtendNG JpaRepository<UserEntity, Long>
,其中UserEntity
是我的模型类。
User
是从弹簧框架中的UserDetails
实现。
和我使用Junit和Mockito编写了此方法的单元测试。这些测试正在工作:
@RunWith(SpringRunner.class)
@DirtiesContext
public class UserDetailsServiceTest {
@Autowired
private UserDetailsService userDetailsService;
@Test
public void shouldFindUser() throws Exception {
// given
final UserEntity user = new UserEntity(
1L,
"username",
"username@email.com",
"password",
new ArrayList<>() // list of roles
);
when(UserDetailsServiceTestContext.userRepository.findByUsername(user.getUsername()))
.thenReturn(user);
// when
final UserDetails result = userDetailsService.loadUserByUsername(user.getUsername());
// then
assertThat(result).isEqualTo(UserFactory.create(user));
verify(UserDetailsServiceTestContext.userRepository)
.findByUsername(user.getUsername());
}
@Test(expected = UsernameNotFoundException.class)
public void shouldNotFindUser() throws Exception {
// given
when(UserDetailsServiceTestContext.userRepository.findByUsername(anyString()))
.thenReturn(null);
// when
final UserDetails result = userDetailsService.loadUserByUsername(new String());
}
@TestConfiguration
static class UserDetailsServiceTestContext {
@MockBean
private static UserRepository userRepository;
@Bean
UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl(userRepository);
}
}
}
现在,我尝试使用Groovy和Spock框架编写这些测试。我写了以下规范:
def 'should find user'() {
given:
def user = new UserEntity(
1L,
"username",
"username@email.com",
"password"
new ArrayList<>() // list of roles
)
userRepository.findByUsername(user.username) >> user
// userRepository.findByUsername(_ as String) >> user // also working
when:
def result = userDetailsService.loadUserByUsername(user.username)
then:
result == new User(user)
}
此测试正在起作用。但是,当我想通过添加 then:
中的添加来验证userrepository的调用时,语句 1 * userRepository.findByUsername(user.username)
或 1 * userRepository.findByUsername(_ as String)
我会收到错误 UserDetailsServiceSpec.should find user and return new User:36 » UsernameNotFound
。第36行是在when:
您需要在一个步骤中进行固执和验证
then:
1 * userRepository.findByUsername(user.username) >> user
有关详细信息,这是我从Spock中的预定义模拟响应中的答案:
请参阅文档
嘲笑和固定相同的方法调用时,它们必须在相同的互动中发生。特别是,以下模仿风格的固执和模拟分为两个单独的陈述将无效:
setup:
subscriber.receive("message1") >> "ok"
when:
publisher.send("message1")
then:
1 * subscriber.receive("message1")
正如在何处声明互动中所述,接收呼叫将首先与当时的块中的交互作用相匹配。由于该交互没有指定响应,因此将返回该方法返回类型的默认值(在这种情况下为NULL)。(这只是Spock宽大嘲笑方法的另一个方面。)。因此,设置:块中的交互永远不会有机会匹配。
在处理春季和交易代理时,您可能还会遇到此问题https://github.com/spockframework/spock/spock/issues/758