2012-01-23 15 views
11

का उपयोग कर स्प्रिंग सर्विस यूनिट परीक्षण अब तक एसओ से जवाब मेरी समस्याओं के लिए पूरी तरह से संतोषजनक रहा है। मैं जूनिट और मॉकिटो के साथ यूनिट परीक्षण सीख रहा हूं और मैं अपनी सेवा कक्षा का परीक्षण करना चाहता हूं जो कि मेरे स्प्रिंग वेब ऐप का हिस्सा है। मैंने कई ट्यूटोरियल और लेख पढ़े और मुझे अभी भी मेरी सेवा परत के लिए उचित यूनिट परीक्षण लिखने में समस्याएं हैं। मैं अपने सवालों के जवाब जानना चाहते हैं, लेकिन पहले मैं कुछ कोड पेस्ट करें:मॉकिटो

सेवा वर्ग

public class AccountServiceImpl implements AccountService { 

@Autowired 
AccountDao accountDao, RoleDao roleDao, PasswordEncoder passwordEncoder, SaltSource saltSource; 

@PersistenceContext 
EntityManager entityManager; 

public Boolean registerNewAccount(Account newAccount) { 
    entityManager.persist(newAccount); 
    newAccount.setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount))); 
    setRoleToAccount("ROLE_REGISTERED", newAccount); 

    return checkIfUsernameExists(newAccount.getUsername());  
} 

public void setRoleToAccount(String roleName, Account account) { 
    List<Role> roles = new ArrayList<Role>(); 
    try { 
     roles.add(roleDao.findRole(roleName)); 
    } catch(RoleNotFoundException rnf) { 
     logger.error(rnf.getMessage()); 
    } 
    account.setRoles(roles); 
} 

public Boolean checkIfUsernameExists(String username) { 
    try { 
     loadUserByUsername(username); 
    } catch(UsernameNotFoundException unf) { 
     return false; 
    } 
    return true; 
} 

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
    try { 
     Account loadedAccount = accountDao.findUsername(username); 
     return loadedAccount; 
    } catch (UserNotFoundException e) { 
     throw new UsernameNotFoundException("User: " + username + "not found!"); 
    } 
} 
} 

मेरे अधूरा परीक्षण वर्ग

@RunWith(MockitoJUnitRunner.class) 
public class AccountServiceImplTest { 

private AccountServiceImpl accountServiceImpl; 
@Mock private Account newAccount; 
@Mock private PasswordEncoder passwordEncoder; 
@Mock private SaltSource saltSource; 
@Mock private EntityManager entityManager; 
@Mock private AccountDao accountDao; 
@Mock private RoleDao roleDao; 

@Before 
public void init() { 
    MockitoAnnotations.initMocks(this); 
    accountServiceImpl = new AccountServiceImpl(); 
    ReflectionTestUtils.setField(accountServiceImpl, "entityManager", entityManager); 
    ReflectionTestUtils.setField(accountServiceImpl, "passwordEncoder", passwordEncoder); 
    ReflectionTestUtils.setField(accountServiceImpl, "saltSource", saltSource); 
    ReflectionTestUtils.setField(accountServiceImpl, "accountDao", accountDao); 
    ReflectionTestUtils.setField(accountServiceImpl, "roleDao", roleDao); 
} 

@Test 
public void testRegisterNewAccount() { 
    Boolean isAccountCreatedSuccessfully = accountServiceImpl.registerNewAccount(newAccount); 

    verify(entityManager).persist(newAccount); 
    verify(newAccount).setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount))); 
    assertTrue(isAccountCreatedSuccessfully); 
} 

@Test 
public void testShouldSetRoleToAccount() throws RoleNotFoundException{ 
    Role role = new Role(); //Maybe I can use mock here? 
    role.setName("ROLE_REGISTERED"); 
    when(roleDao.findRole("ROLE_REGISTERED")).thenReturn(role); 
    accountServiceImpl.setRoleToAccount("ROLE_REGISTERED", newAccount); 
    assertTrue(newAccount.getRoles().contains(role)); 
} 

} 

प्रश्न :

  1. यूनिट परीक्षण करने का सबसे अच्छा तरीका क्या है जहां मेरी सेवा कक्षा में विधियों में विधियां हैं? क्या मैं उन्हें ऊपर की तरह अलग से परीक्षण कर सकता हूं? [मैंने क्लीनर कोड रखने के लिए अपने कोड को कुछ तरीकों से विभाजित किया]
  2. क्या testRegisterNewAccount() मेरी सेवा विधि के लिए अच्छा यूनिट परीक्षण है? टेस्ट हरा है हालांकि मुझे इसके बारे में निश्चित नहीं है।
  3. मुझे अपने testShouldSetRoleToAccount में विफलता मिल रही है। मैं क्या गलत कर रहा हूं?
  4. checkIfUsernameExists का परीक्षण कैसे करें?

हो सकता है कि किसी ने मुझे इस के साथ मदद मिलेगी, क्योंकि मैं कुछ दिनों के खर्च और मैं एक प्रगति :(


अद्यतन नहीं किया

समाप्त परीक्षण वर्ग

@RunWith(MockitoJUnitRunner.class) 
public class AccountServiceImplTest extends BaseTest { 

private AccountServiceImpl accountServiceImpl; 
private Role role; 
private Account account; 
@Mock private Account newAccount; 
@Mock private PasswordEncoder passwordEncoder; 
@Mock private SaltSource saltSource; 
@Mock private EntityManager entityManager; 
@Mock private AccountDao accountDao; 
@Mock private RoleDao roleDao; 

@Before 
public void init() { 
    accountServiceImpl = new AccountServiceImpl(); 
    role = new Role(); 
    account = new Account(); 
    ReflectionTestUtils.setField(accountServiceImpl, "entityManager", entityManager); 
    ReflectionTestUtils.setField(accountServiceImpl, "passwordEncoder", passwordEncoder); 
    ReflectionTestUtils.setField(accountServiceImpl, "saltSource", saltSource); 
    ReflectionTestUtils.setField(accountServiceImpl, "accountDao", accountDao); 
    ReflectionTestUtils.setField(accountServiceImpl, "roleDao", roleDao); 
} 

@Test 
public void testShouldRegisterNewAccount() { 
    Boolean isAccountCreatedSuccessfully = accountServiceImpl.registerNewAccount(newAccount); 

    verify(entityManager).persist(newAccount); 
    verify(newAccount).setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount))); 
    assertTrue(isAccountCreatedSuccessfully); 
} 

@Test(expected = IllegalArgumentException.class) 
public void testShouldNotRegisterNewAccount() { 
    doThrow(new IllegalArgumentException()).when(entityManager).persist(account); 
    accountServiceImpl.registerNewAccount(account); 
} 

@Test 
public void testShouldSetRoleToAccount() throws RoleNotFoundException { 
    when(roleDao.findRole(anyString())).thenReturn(role); 
    accountServiceImpl.setRoleToAccount("ROLE_REGISTERED", account); 
    assertTrue(account.getRoles().contains(role)); 
} 

@Test 
public void testShouldNotSetRoleToAccount() throws RoleNotFoundException { 
    when(roleDao.findRole(anyString())).thenThrow(new RoleNotFoundException()); 
    accountServiceImpl.setRoleToAccount("ROLE_RANDOM", account); 
    assertFalse(account.getRoles().contains(role)); 
} 

@Test 
public void testCheckIfUsernameExistsIsTrue() throws UserNotFoundException { 
    when(accountDao.findUsername(anyString())).thenReturn(account); 
    Boolean userExists = accountServiceImpl.checkIfUsernameExists(anyString()); 
    assertTrue(userExists); 
} 

@Test 
public void testCheckIfUsernameExistsIsFalse() throws UserNotFoundException { 
    when(accountDao.findUsername(anyString())).thenThrow(new UserNotFoundException()); 
    Boolean userExists = accountServiceImpl.checkIfUsernameExists(anyString()); 
    assertFalse(userExists); 
} 

@Test 
public void testShouldLoadUserByUsername() throws UserNotFoundException { 
    when(accountDao.findUsername(anyString())).thenReturn(account); 
    Account foundAccount = (Account) accountServiceImpl.loadUserByUsername(anyString()); 
    assertEquals(account, foundAccount); 
} 

@Test(expected = UsernameNotFoundException.class) 
public void testShouldNotLoadUserByUsername() throws UserNotFoundException { 
    when(accountDao.findUsername(anyString())).thenThrow(new UsernameNotFoundException(null)); 
    accountServiceImpl.loadUserByUsername(anyString()); 
} 

} 

उत्तर

5

प्रश्न 1 - आपके पास एक जोड़ा है यहां विकल्पों का।

विकल्प 1 - उस व्यवहार के लिए आवश्यकतानुसार प्रत्येक सार्वजनिक विधि के प्रत्येक व्यवहार के लिए अलग-अलग परीक्षण लिखें। यह प्रत्येक परीक्षण को साफ और अलग रखता है, लेकिन इसका मतलब यह है कि माध्यमिक तरीकों में तर्क (जैसे checkIfUsernameExists) का प्रयोग दो बार किया जाएगा। एक मायने में, यह अनावश्यक नकल है, लेकिन इस विकल्प का एक फायदा यह है कि यदि आप कार्यान्वयन को बदलते हैं, लेकिन आवश्यक व्यवहार नहीं है, तो आपके पास अभी भी व्यवहार के आधार पर अच्छे परीक्षण होंगे।

विकल्प 2 - एक मॉकिटो जासूस का उपयोग करें। यह एक नकली की तरह थोड़ा है, सिवाय इसके कि आप इसे एक वास्तविक वस्तु से बनाते हैं, और इसका डिफ़ॉल्ट व्यवहार यह है कि सभी विधियां सामान्य रूप से चलती हैं। फिर आप उन्हें कॉल करने वाले तरीकों का परीक्षण करने के लिए द्वितीयक तरीकों को रोक और सत्यापित कर सकते हैं।

प्रश्न 2 - यह registerNewAccount के "सफलता" मामले के लिए एक अच्छा परीक्षण की तरह दिखता है। कृपया असफल होने और झूठी वापसी के लिए registerNewAccount का कारण क्या होगा, इसके बारे में सोचें; और इस मामले का परीक्षण करें।

प्रश्न 3 - मुझे इस पर कोई अच्छा नज़र नहीं पड़ा है; लेकिन डीबगर के साथ चलने का प्रयास करें, और पता लगाएं कि आपकी ऑब्जेक्ट्स आपकी अपेक्षा से अलग है। यदि आप इसे काम नहीं कर सकते हैं, तो फिर से पोस्ट करें और मेरे पास एक और नजर आएगी।

प्रश्न 4 - नकारात्मक मामले का परीक्षण करने के लिए, आवश्यक अपवाद फेंकने के लिए AccountDao के अपने नकली को दबाएं। अन्यथा, प्रश्न 1 के लिए मेरे उत्तर देखें।

+0

धन्यवाद डेविड। प्रश्न 1 का उत्तर दें मैं पूरी तरह से समझता हूं और मैंने विकल्प 1 चुना है। प्रश्न 3 के बारे में मैंने एक समस्या हल करने में कामयाब रहे। मुझे नए ऑपरेटर द्वारा बनाए गए खाते के साथ नकली खाता बदलना पड़ा और यह था [एसआईसी!] :)। प्रश्न 4 ने भी मेरी मदद की, लेकिन मुझे अन्य समस्याएं हैं। जैसा कि आप अपने संकेतों के लिए धन्यवाद देख सकते हैं, मैंने अपने सभी तरीकों के लिए परीक्षण लिखने में कामयाब रहे। वे testShouldNotSetRoleToAccount और testShouldNotLoadUserByUsername को छोड़कर ठीक काम करते हैं। जब "अपेक्षित = ..." होता है तो दोनों विफल हो जाते हैं। इसके बिना ठीक है। इसके अलावा पहले भी त्रुटि बनाता है और परीक्षण त्रुटि है। क्या तुम मेरी मदद कर सकते हो? –

+0

क्षमा करें मुझे वापस आने के लिए मुझे थोड़ी देर लग गई है। यदि वे परीक्षण अपेक्षित अपवाद सेट के साथ विफल हो जाते हैं, तो इसका मतलब है कि अपवाद वास्तव में फेंक नहीं रहा है। क्या आप वाकई 'रोलडाओ' और 'अकाउंटडाओ' को वास्तव में मोक्स पर सेट कर चुके हैं? आप इसे डीबगर के साथ देख सकते हैं। साथ ही, आप 'anyString()' का सही ढंग से उपयोग नहीं कर रहे हैं - यह वास्तव में आपकी विधि को चलाने के लिए, स्टबिंग और सत्यापन के लिए है; मुझे नहीं पता कि यह आपकी समस्या का कारण है या नहीं। उन लाइनों में जहां आप वास्तव में अपनी विधियों को चलाते हैं, वास्तविक मूल्य डाल दें जिसे आप पास करना चाहते हैं, 'anyString() 'के बजाय। –

+0

एह लॉल, मैं बेवकूफ हूँ। यह त्रुटि जो मैं इसके बारे में बात कर रहा था वह केवल लॉगर से कंसोल जानकारी थी। भूमिका में जब अपवाद पकड़ा जाता है तो वहां लॉगजर होता है। आतंक (..): पी। मैंने अपने टेस्ट कोड को अच्छी तरह से देखा और अब सबकुछ ठीक है। testShouldNotSetRoleToAccount और testCheckIfUsernameExistsIsFalse में "अपेक्षित" की आवश्यकता नहीं है। बाद में मैं अपनी टेस्ट क्लास अपडेट करूंगा और हम इस चर्चा को बंद कर सकते हैं। एक बार डेविड धन्यवाद, आपके संकेत बहुत उपयोगी थे :) –

संबंधित मुद्दे