2017-09-03 162 views
0

我有春天接口UserDetailsService的實現:我不能改寫的Mockito單元測試斯波克規格

@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是來自Spring Framework的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", 
       "[email protected]", 
       "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", 
       "[email protected]", 
       "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:中添加一條語句1 * userRepository.findByUsername(user.username)1 * userRepository.findByUsername(_ as String)來驗證userRepository的調用時,我收到一個錯誤UserDetailsServiceSpec.should find user and return new User:36 » UsernameNotFound。管線36節when:

回答

1

你需要做的磕碰和驗證一個步驟

then: 
1 * userRepository.findByUsername(user.username) >> user 

對於這裏的細節是Predefined mock response in Spock我的回答:

請參閱documentation

當模擬和存根相同的方法調用時,它們必須發生在相同的交互中。特別是,磕碰和嘲笑成兩個獨立的語句下面的Mockito式的分裂將無法正常工作:

setup: 
subscriber.receive("message1") >> "ok" 

when: 
publisher.send("message1") 

then: 
1 * subscriber.receive("message1") 

正如在哪裏聲明互動解釋,接收電話將首先獲得對互動匹配在then:塊中。由於該交互沒有指定響應,因此將返回方法返回類型的默認值(在這種情況下爲null)。 (這只是Spock寬鬆處理嘲笑的另一個方面)。因此,setup:block中的交互永遠不會有匹配的機會。


當春天的交易和交易代理,你也可能碰到這個問題https://github.com/spockframework/spock/issues/758

相關問題