2012-01-23 32 views
11

Cho đến bây giờ các câu trả lời từ SO đã hoàn toàn thỏa mãn các vấn đề của tôi. Tôi đang học thử nghiệm đơn vị với Junit và Mockito và tôi muốn kiểm tra lớp dịch vụ của mình, một phần của ứng dụng web Spring của tôi. Tôi đã đọc nhiều bài hướng dẫn và bài viết và tôi vẫn gặp vấn đề khi viết các bài kiểm tra đơn vị thích hợp cho lớp dịch vụ của mình. Tôi muốn biết câu trả lời cho câu hỏi của tôi, nhưng trước tiên tôi dán một số mã:Thử nghiệm đơn vị dịch vụ mùa xuân bằng cách sử dụng mockito

lớp Service

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!"); 
    } 
} 
} 

dở dang lớp thử nghiệm của tôi

@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)); 
} 

} 

Câu hỏi :

  1. Cách tốt nhất để thực hiện các bài kiểm tra đơn vị nơi tôi có phương pháp trong các phương pháp như trong lớp dịch vụ của tôi là gì? Tôi có thể kiểm tra chúng một cách riêng biệt như trên không? [Tôi đã chia mã của mình thành một vài phương pháp để có mã sạch hơn]
  2. Có phải testRegisterNewAccount() kiểm tra đơn vị tốt cho phương thức dịch vụ của tôi không? Kiểm tra là màu xanh lá cây tuy nhiên tôi không chắc chắn về nó.
  3. Tôi nhận được lỗi trong testShouldSetRoleToAccount của mình. Tôi đang làm gì sai?
  4. Cách kiểm tra checkIfUsernameExists?

Có lẽ ai đó sẽ giúp tôi với điều này vì tôi đã dành một vài ngày và tôi đã không làm cho một sự tiến bộ :(


CẬP NHẬT

lớp thử nghiệm Hoàn

@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()); 
} 

} 

Trả lời

5

Câu hỏi 1 - Bạn đã có một cặp vợ chồng các tùy chọn ở đây.

Tùy chọn 1 - viết các bài kiểm tra riêng cho từng hành vi của từng phương pháp công khai, dựa trên những gì cần thiết cho hành vi đó. Điều này giữ cho mỗi bài kiểm tra sạch sẽ và riêng biệt, nhưng nó có nghĩa là logic trong phương pháp thứ cấp (chẳng hạn như checkIfUsernameExists) sẽ được thực hiện hai lần. Trong một nghĩa nào đó, đây là sự sao chép không cần thiết, nhưng một ưu điểm của tùy chọn này là nếu bạn thay đổi việc thực hiện, nhưng không phải là hành vi bắt buộc, bạn vẫn sẽ có các thử nghiệm tốt dựa trên hành vi đó.

Tùy chọn 2 - sử dụng Trình mô phỏng Mockito. Đây là một chút giống như một giả, ngoại trừ việc bạn tạo nó từ một đối tượng thực, và hành vi mặc định của nó là tất cả các phương thức chạy như bình thường. Sau đó bạn có thể thoát ra và xác minh các phương thức thứ cấp, để kiểm tra các phương thức gọi chúng.

Câu hỏi 2 - Điều này giống như một thử nghiệm tốt cho trường hợp "thành công" của registerNewAccount. Hãy suy nghĩ về hoàn cảnh nào sẽ khiến cho registerNewAccount thất bại và trả về false; và kiểm tra trường hợp này.

Câu hỏi 3 - Tôi chưa có cái nhìn tốt về điều này; nhưng hãy thử chạy với trình gỡ rối và tìm hiểu tại thời điểm đó các đối tượng của bạn khác với những gì bạn mong đợi. Nếu bạn không thể làm việc, hãy đăng lại và tôi sẽ có một cái nhìn khác.

Câu hỏi 4 - Để kiểm tra trường hợp phủ định, hãy thử mô hình AccountDao để ném ngoại lệ bắt buộc. Nếu không, hãy xem câu trả lời cho câu hỏi của tôi 1.

+0

Cảm ơn David. Trả lời câu hỏi 1 tôi hoàn toàn hiểu và tôi đã chọn tùy chọn 1. Về Câu hỏi 3 Tôi đã giải quyết được vấn đề. Tôi đã phải thay thế Tài khoản giả bằng Tài khoản được tạo bởi toán tử mới và nó là [sic!] :). Câu hỏi 4 cũng đã giúp tôi, nhưng tôi có những vấn đề khác. Như bạn có thể thấy nhờ những gợi ý của bạn, tôi đã viết các bài kiểm tra cho tất cả các phương pháp của mình. Họ làm việc ok trừ testShouldNotSetRoleToAccount và testShouldNotLoadUserByUsername. Cả hai đều thất bại khi có "expected = ...". Không có nó ok. Hơn nữa đầu tiên cũng làm cho vi lỗi và thử nghiệm là Lỗi. Bạn có thể giúp tôi? –

+0

Rất tiếc, tôi đã mất một lúc để liên hệ lại với bạn. Nếu những kiểm tra đó thất bại với tập hợp ngoại lệ dự kiến, điều đó có nghĩa là ngoại lệ không thực sự bị ném. Bạn có chắc chắn rằng 'roleDao' và' accountDao' đã thực sự được đặt thành mocks không? Bạn có thể kiểm tra điều này với trình gỡ rối. Ngoài ra, bạn không sử dụng 'anyString()' một cách chính xác - điều này là để stubbing và xác minh, không thực sự chạy phương thức của bạn; Tôi không biết đây có phải là nguyên nhân của vấn đề của bạn hay không. Trong các dòng nơi bạn thực sự chạy các phương thức của mình, hãy đặt giá trị thực mà bạn muốn chuyển, thay vì 'anyString()'. –

+0

Eh lol, tôi ngu ngốc. Lỗi này mà tôi đã nói về nó chỉ là thông tin bàn điều khiển từ logger. Trong roleDao khi ngoại lệ bị bắt, có logger.error (..): P. Tôi nhìn vào mã kiểm tra của tôi kỹ lưỡng và bây giờ mọi thứ đều ổn. "mong đợi" trong testShouldNotSetRoleToAccount và testCheckIfUsernameExistsIsFalse là không cần thiết. Sau đó tôi sẽ cập nhật lớp thử nghiệm của mình và chúng tôi có thể đóng cuộc thảo luận này. Cảm ơn một lần nữa David, gợi ý của bạn rất hữu ích :) –

Các vấn đề liên quan