2014-03-25 36 views
0

我想用Spring定義一個我自己的組件。定義Spring組件時出錯

下面有我的代碼:

MyPasswordEncoderConfig

@Configuration 
@ComponentScan(basePackages = { "my.package" }) 
public class CryptoConfig { 

    @Bean 
    public PasswordEncoder getPasswordEncoder() { 
     return new BCryptPasswordEncoder(); 
    } 

} 

MyPasswordEncoder

@Component 
public class MyPasswordEncoder { 

    @Autowired 
    private PasswordEncoder passwordEncoder; // Defined in Spring Security. 

    public String encode(String plainTextPassword) { 
     return passwordEncoder.encode(plainTextPassword); 
    } 

    public boolean matches(String encodedPasswordA, String encodedPasswordB) { 
     return passwordEncoder.matches(encodedPasswordA, encodedPasswordB); 
    } 

} 

MyPasswordEncoderTest

@ContextConfiguration(classes = {MyPasswordEncoder.class, MyPasswordEncoderConfig.class}) 
@RunWith(SpringJUnit4ClassRunner.class) 
public class MyPasswordEncoderTest { 

    @Mock 
    private PasswordEncoder passwordEncoder; 

    @InjectMocks 
    @Autowired 
    private MyPasswordEncoder myPasswordEncoder; 

    @Before 
    public void init() { 
     MockitoAnnotations.initMocks(this); 
    } 

    @Test 
    public void testPasswordMatching() { 
     String plainTextPassword = "[email protected]@@"; 
     String encodedPassword = myPasswordEncoder.encode(plainTextPassword); 
     assertTrue(myPasswordEncoder.matches(plainTextPassword, encodedPassword)); 
    } 
} 

當我運行測試時,它失敗。使用標準輸出檢查結果,passwordEncoder.encode(plainTextPassword);返回空值。

我在做什麼錯?

UPDATE:

問題是關於的PasswordEncoder接口。如果我用替換它BCryptPasswordEncoder,測試工作正常。

+0

你認爲它應該返回,爲什麼? –

+0

它必須使用BCrypt算法返回散列。 – vdenotaris

+0

你覺得'@ Mock'有什麼用?你認爲'InjectMocks'有什麼作用? –

回答

2

從我從您的測試代碼中收集的內容中,您實際上想要測試MyPasswordEncoder的功能。那麼爲什麼要使用模擬? 爲什麼不直接使用@Autowired兩個PasswordEncoderMyPasswordEncoder像下面的代碼:

@ContextConfiguration(classes = {MyPasswordEncoder.class, MyPasswordEncoderConfig.class}) 
@RunWith(SpringJUnit4ClassRunner.class) 
public class MyPasswordEncoderTest { 

     @Autowired 
     private PasswordEncoder passwordEncoder; 

     @Autowired 
     private MyPasswordEncoder myPasswordEncoder; 

     @Test 
     public void testPasswordMatching() { 
      String plainTextPassword = "[email protected]@@"; 
      String encodedPassword = myPasswordEncoder.encode(plainTextPassword); 
      assertTrue(myPasswordEncoder.matches(plainTextPassword, encodedPassword)); 
     } 
    } 

如果你不想寫彈簧集成測試,但一個簡單的單元測試,不希望重構代碼,你可以寫:

public class MyPasswordEncoderTest { 

    private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 

    private MyPasswordEncoder myPasswordEncoder = new MyPasswordEncoder(); 

    @Before 
    public void init() { 
     ReflectionTestUtils.setField(myPasswordEncoder, "passwordEncoder", passwordEncoder); 
    } 

    @Test 
    public void testPasswordMatching() { 
     String plainTextPassword = "[email protected]@@"; 
     String encodedPassword = myPasswordEncoder.encode(plainTextPassword); 
     assertTrue(myPasswordEncoder.matches(plainTextPassword, encodedPassword)); 
    } 
} 

一個更好的解決方案(其中溝渠使用Spring ReflectionTestUtils的)是重構MyPasswordEncoder像這樣:

@Component 
public class MyPasswordEncoder { 

    private final PasswordEncoder passwordEncoder; // Defined in Spring Security. 

    @Autowired 
    public MyPasswordEncoder(PasswordEncoder passwordEncoder) { 
     this.passwordEncoder = passwordEncoder; 
    } 

    public String encode(String plainTextPassword) { 
     return passwordEncoder.encode(plainTextPassword); 
    } 

    public boolean matches(String encodedPasswordA, String encodedPasswordB) { 
     return passwordEncoder.matches(encodedPasswordA, encodedPasswordB); 
    } 

} 

然後單元測試將變成:

public class MyPasswordEncoderTest { 

    private MyPasswordEncoder myPasswordEncoder = new MyPasswordEncoder(new BCryptPasswordEncoder()); 

    @Test 
    public void testPasswordMatching() { 
     String plainTextPassword = "[email protected]@@"; 
     String encodedPassword = myPasswordEncoder.encode(plainTextPassword); 
     assertTrue(myPasswordEncoder.matches(plainTextPassword, encodedPassword)); 
    } 
} 
1

的這裏的問題是,由於@InjectMocks,正被注入實際PasswordEncoder@Mock

@Mock 
private PasswordEncoder passwordEncoder; 

不是一個你@Configuration類。 (實際上,兩者都被注入,但最後注入的是模擬,所以這就是使用的那個)。你可以驗證這個(如果該字段是可見的)。

System.out.println(MyPasswordEncoder.passwordEncoder.getClass()); 

將打印像

class com.spring.PasswordEncoder$$EnhancerByMockitoWithCGLIB$$7d70b580 
// pay attention to    ^  this part  ^

嘲笑通常被實現返回null對於引用類型,0的數字原語和false布爾。

相關問題